no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / toolkit / content / aboutNetworking.js
blobd33d0cc88b5f23c85724f898d67a6d6a55af2677
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 "use strict";
7 const FileUtils = ChromeUtils.importESModule(
8   "resource://gre/modules/FileUtils.sys.mjs"
9 ).FileUtils;
10 const gDashboard = Cc["@mozilla.org/network/dashboard;1"].getService(
11   Ci.nsIDashboard
13 const gDirServ = Cc["@mozilla.org/file/directory_service;1"].getService(
14   Ci.nsIDirectoryServiceProvider
16 const gNetLinkSvc =
17   Cc["@mozilla.org/network/network-link-service;1"] &&
18   Cc["@mozilla.org/network/network-link-service;1"].getService(
19     Ci.nsINetworkLinkService
20   );
22 const gRequestNetworkingData = {
23   http: gDashboard.requestHttpConnections,
24   sockets: gDashboard.requestSockets,
25   dns: gDashboard.requestDNSInfo,
26   websockets: gDashboard.requestWebsocketConnections,
27   dnslookuptool: () => {},
28   rcwn: gDashboard.requestRcwnStats,
29   networkid: displayNetworkID,
31 const gDashboardCallbacks = {
32   http: displayHttp,
33   sockets: displaySockets,
34   dns: displayDns,
35   websockets: displayWebsockets,
36   rcwn: displayRcwnStats,
39 const REFRESH_INTERVAL_MS = 3000;
41 function col(element) {
42   let col = document.createElement("td");
43   let content = document.createTextNode(element);
44   col.appendChild(content);
45   return col;
48 function displayHttp(data) {
49   let cont = document.getElementById("http_content");
50   let parent = cont.parentNode;
51   let new_cont = document.createElement("tbody");
52   new_cont.setAttribute("id", "http_content");
54   for (let i = 0; i < data.connections.length; i++) {
55     let row = document.createElement("tr");
56     row.appendChild(col(data.connections[i].host));
57     row.appendChild(col(data.connections[i].port));
58     row.appendChild(col(data.connections[i].httpVersion));
59     row.appendChild(col(data.connections[i].ssl));
60     row.appendChild(col(data.connections[i].active.length));
61     row.appendChild(col(data.connections[i].idle.length));
62     new_cont.appendChild(row);
63   }
65   parent.replaceChild(new_cont, cont);
68 function displaySockets(data) {
69   let cont = document.getElementById("sockets_content");
70   let parent = cont.parentNode;
71   let new_cont = document.createElement("tbody");
72   new_cont.setAttribute("id", "sockets_content");
74   for (let i = 0; i < data.sockets.length; i++) {
75     let row = document.createElement("tr");
76     row.appendChild(col(data.sockets[i].host));
77     row.appendChild(col(data.sockets[i].port));
78     row.appendChild(col(data.sockets[i].type));
79     row.appendChild(col(data.sockets[i].active));
80     row.appendChild(col(data.sockets[i].sent));
81     row.appendChild(col(data.sockets[i].received));
82     new_cont.appendChild(row);
83   }
85   parent.replaceChild(new_cont, cont);
88 function displayDns(data) {
89   let suffixContent = document.getElementById("dns_suffix_content");
90   let suffixParent = suffixContent.parentNode;
91   let suffixes = [];
92   try {
93     suffixes = gNetLinkSvc.dnsSuffixList; // May throw
94   } catch (e) {}
95   let suffix_tbody = document.createElement("tbody");
96   suffix_tbody.id = "dns_suffix_content";
97   for (let suffix of suffixes) {
98     let row = document.createElement("tr");
99     row.appendChild(col(suffix));
100     suffix_tbody.appendChild(row);
101   }
102   suffixParent.replaceChild(suffix_tbody, suffixContent);
104   let trr_url_tbody = document.createElement("tbody");
105   trr_url_tbody.id = "dns_trr_url";
106   let trr_url = document.createElement("tr");
107   trr_url.appendChild(col(Services.dns.currentTrrURI));
108   trr_url.appendChild(col(Services.dns.currentTrrMode));
109   trr_url_tbody.appendChild(trr_url);
110   let prevURL = document.getElementById("dns_trr_url");
111   prevURL.parentNode.replaceChild(trr_url_tbody, prevURL);
113   let cont = document.getElementById("dns_content");
114   let parent = cont.parentNode;
115   let new_cont = document.createElement("tbody");
116   new_cont.setAttribute("id", "dns_content");
118   for (let i = 0; i < data.entries.length; i++) {
119     let row = document.createElement("tr");
120     row.appendChild(col(data.entries[i].hostname));
121     row.appendChild(col(data.entries[i].family));
122     row.appendChild(col(data.entries[i].trr));
123     let column = document.createElement("td");
125     for (let j = 0; j < data.entries[i].hostaddr.length; j++) {
126       column.appendChild(document.createTextNode(data.entries[i].hostaddr[j]));
127       column.appendChild(document.createElement("br"));
128     }
130     row.appendChild(column);
131     row.appendChild(col(data.entries[i].expiration));
132     row.appendChild(col(data.entries[i].originAttributesSuffix));
133     row.appendChild(col(data.entries[i].flags));
134     new_cont.appendChild(row);
135   }
137   parent.replaceChild(new_cont, cont);
140 function displayWebsockets(data) {
141   let cont = document.getElementById("websockets_content");
142   let parent = cont.parentNode;
143   let new_cont = document.createElement("tbody");
144   new_cont.setAttribute("id", "websockets_content");
146   for (let i = 0; i < data.websockets.length; i++) {
147     let row = document.createElement("tr");
148     row.appendChild(col(data.websockets[i].hostport));
149     row.appendChild(col(data.websockets[i].encrypted));
150     row.appendChild(col(data.websockets[i].msgsent));
151     row.appendChild(col(data.websockets[i].msgreceived));
152     row.appendChild(col(data.websockets[i].sentsize));
153     row.appendChild(col(data.websockets[i].receivedsize));
154     new_cont.appendChild(row);
155   }
157   parent.replaceChild(new_cont, cont);
160 function displayRcwnStats(data) {
161   let status = Services.prefs.getBoolPref("network.http.rcwn.enabled");
162   let linkType = Ci.nsINetworkLinkService.LINK_TYPE_UNKNOWN;
163   try {
164     linkType = gNetLinkSvc.linkType;
165   } catch (e) {}
166   if (
167     !(
168       linkType == Ci.nsINetworkLinkService.LINK_TYPE_UNKNOWN ||
169       linkType == Ci.nsINetworkLinkService.LINK_TYPE_ETHERNET ||
170       linkType == Ci.nsINetworkLinkService.LINK_TYPE_USB ||
171       linkType == Ci.nsINetworkLinkService.LINK_TYPE_WIFI
172     )
173   ) {
174     status = false;
175   }
177   let cacheWon = data.rcwnCacheWonCount;
178   let netWon = data.rcwnNetWonCount;
179   let total = data.totalNetworkRequests;
180   let cacheSlow = data.cacheSlowCount;
181   let cacheNotSlow = data.cacheNotSlowCount;
183   document.getElementById("rcwn_status").innerText = status;
184   document.getElementById("total_req_count").innerText = total;
185   document.getElementById("rcwn_cache_won_count").innerText = cacheWon;
186   document.getElementById("rcwn_cache_net_count").innerText = netWon;
187   document.getElementById("rcwn_cache_slow").innerText = cacheSlow;
188   document.getElementById("rcwn_cache_not_slow").innerText = cacheNotSlow;
190   // Keep in sync with CachePerfStats::EDataType in CacheFileUtils.h
191   const perfStatTypes = ["open", "read", "write", "entryopen"];
193   const perfStatFieldNames = ["avgShort", "avgLong", "stddevLong"];
195   for (let typeIndex in perfStatTypes) {
196     for (let statFieldIndex in perfStatFieldNames) {
197       document.getElementById(
198         "rcwn_perfstats_" +
199           perfStatTypes[typeIndex] +
200           "_" +
201           perfStatFieldNames[statFieldIndex]
202       ).innerText =
203         data.perfStats[typeIndex][perfStatFieldNames[statFieldIndex]];
204     }
205   }
208 function displayNetworkID() {
209   try {
210     let linkIsUp = gNetLinkSvc.isLinkUp;
211     let linkStatusKnown = gNetLinkSvc.linkStatusKnown;
212     let networkID = gNetLinkSvc.networkID;
214     document.getElementById("networkid_isUp").innerText = linkIsUp;
215     document.getElementById("networkid_statusKnown").innerText =
216       linkStatusKnown;
217     document.getElementById("networkid_id").innerText = networkID;
218   } catch (e) {
219     document.getElementById("networkid_isUp").innerText = "<unknown>";
220     document.getElementById("networkid_statusKnown").innerText = "<unknown>";
221     document.getElementById("networkid_id").innerText = "<unknown>";
222   }
225 function requestAllNetworkingData() {
226   for (let id in gRequestNetworkingData) {
227     requestNetworkingDataForTab(id);
228   }
231 function requestNetworkingDataForTab(id) {
232   gRequestNetworkingData[id](gDashboardCallbacks[id]);
235 let gInited = false;
236 function init() {
237   if (gInited) {
238     return;
239   }
240   gInited = true;
242   requestAllNetworkingData();
244   let autoRefresh = document.getElementById("autorefcheck");
245   if (autoRefresh.checked) {
246     setAutoRefreshInterval(autoRefresh);
247   }
249   autoRefresh.addEventListener("click", function () {
250     let refrButton = document.getElementById("refreshButton");
251     if (this.checked) {
252       setAutoRefreshInterval(this);
253       refrButton.disabled = "disabled";
254     } else {
255       clearInterval(this.interval);
256       refrButton.disabled = null;
257     }
258   });
260   let refr = document.getElementById("refreshButton");
261   refr.addEventListener("click", requestAllNetworkingData);
262   if (document.getElementById("autorefcheck").checked) {
263     refr.disabled = "disabled";
264   }
266   // Event delegation on #categories element
267   let menu = document.getElementById("categories");
268   menu.addEventListener("click", function click(e) {
269     if (e.target && e.target.parentNode == menu) {
270       show(e.target);
271     }
272   });
274   let dnsLookupButton = document.getElementById("dnsLookupButton");
275   dnsLookupButton.addEventListener("click", function () {
276     doLookup();
277   });
279   let clearDNSCache = document.getElementById("clearDNSCache");
280   clearDNSCache.addEventListener("click", function () {
281     Services.dns.clearCache(true);
282   });
284   if (location.hash) {
285     let sectionButton = document.getElementById(
286       "category-" + location.hash.substring(1)
287     );
288     if (sectionButton) {
289       sectionButton.click();
290     }
291   }
294 function show(button) {
295   let current_tab = document.querySelector(".active");
296   let category = button.getAttribute("id").substring("category-".length);
297   let content = document.getElementById(category);
298   if (current_tab == content) {
299     return;
300   }
301   current_tab.classList.remove("active");
302   current_tab.hidden = true;
303   content.classList.add("active");
304   content.hidden = false;
306   let current_button = document.querySelector("[selected=true]");
307   current_button.removeAttribute("selected");
308   button.setAttribute("selected", "true");
310   let autoRefresh = document.getElementById("autorefcheck");
311   if (autoRefresh.checked) {
312     clearInterval(autoRefresh.interval);
313     setAutoRefreshInterval(autoRefresh);
314   }
316   let title = document.getElementById("sectionTitle");
317   title.textContent = button.children[0].textContent;
318   location.hash = category;
321 function setAutoRefreshInterval(checkBox) {
322   let active_tab = document.querySelector(".active");
323   checkBox.interval = setInterval(function () {
324     requestNetworkingDataForTab(active_tab.id);
325   }, REFRESH_INTERVAL_MS);
328 // We use the pageshow event instead of onload. This is needed because sometimes
329 // the page is loaded via session-restore/bfcache. In such cases we need to call
330 // init() to keep the page behaviour consistent with the ticked checkboxes.
331 // Mostly the issue is with the autorefresh checkbox.
332 window.addEventListener("pageshow", function () {
333   init();
336 function doLookup() {
337   let host = document.getElementById("host").value;
338   if (host) {
339     try {
340       gDashboard.requestDNSLookup(host, displayDNSLookup);
341     } catch (e) {}
342     try {
343       gDashboard.requestDNSHTTPSRRLookup(host, displayHTTPSRRLookup);
344     } catch (e) {}
345   }
348 function displayDNSLookup(data) {
349   let cont = document.getElementById("dnslookuptool_content");
350   let parent = cont.parentNode;
351   let new_cont = document.createElement("tbody");
352   new_cont.setAttribute("id", "dnslookuptool_content");
354   if (data.answer) {
355     for (let address of data.address) {
356       let row = document.createElement("tr");
357       row.appendChild(col(address));
358       new_cont.appendChild(row);
359     }
360   } else {
361     new_cont.appendChild(col(data.error));
362   }
364   parent.replaceChild(new_cont, cont);
367 function displayHTTPSRRLookup(data) {
368   let cont = document.getElementById("https_rr_content");
369   let parent = cont.parentNode;
370   let new_cont = document.createElement("tbody");
371   new_cont.setAttribute("id", "https_rr_content");
373   if (data.answer) {
374     for (let record of data.records) {
375       let row = document.createElement("tr");
376       let alpn = record.alpn ? `alpn="${record.alpn.alpn}" ` : "";
377       let noDefaultAlpn = record.noDefaultAlpn ? "noDefaultAlpn " : "";
378       let port = record.port ? `port="${record.port.port}" ` : "";
379       let echConfig = record.echConfig
380         ? `echConfig="${record.echConfig.echConfig}" `
381         : "";
382       let ODoHConfig = record.ODoHConfig
383         ? `odoh="${record.ODoHConfig.ODoHConfig}" `
384         : "";
385       let ipv4hint = "";
386       let ipv6hint = "";
387       if (record.ipv4Hint) {
388         let ipv4Str = "";
389         for (let addr of record.ipv4Hint.address) {
390           ipv4Str += `${addr}, `;
391         }
392         // Remove ", " at the end.
393         ipv4Str = ipv4Str.slice(0, -2);
394         ipv4hint = `ipv4hint="${ipv4Str}" `;
395       }
396       if (record.ipv6Hint) {
397         let ipv6Str = "";
398         for (let addr of record.ipv6Hint.address) {
399           ipv6Str += `${addr}, `;
400         }
401         // Remove ", " at the end.
402         ipv6Str = ipv6Str.slice(0, -2);
403         ipv6hint = `ipv6hint="${ipv6Str}" `;
404       }
406       let str = `${record.priority} ${record.targetName} `;
407       str += `(${alpn}${noDefaultAlpn}${port}`;
408       str += `${ipv4hint}${echConfig}${ipv6hint}`;
409       str += `${ODoHConfig})`;
410       row.appendChild(col(str));
411       new_cont.appendChild(row);
412     }
413   } else {
414     new_cont.appendChild(col(data.error));
415   }
417   parent.replaceChild(new_cont, cont);