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/. */
7 const FileUtils = ChromeUtils.importESModule(
8 "resource://gre/modules/FileUtils.sys.mjs"
10 const gDashboard = Cc["@mozilla.org/network/dashboard;1"].getService(
13 const gDirServ = Cc["@mozilla.org/file/directory_service;1"].getService(
14 Ci.nsIDirectoryServiceProvider
17 Cc["@mozilla.org/network/network-link-service;1"] &&
18 Cc["@mozilla.org/network/network-link-service;1"].getService(
19 Ci.nsINetworkLinkService
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 = {
33 sockets: displaySockets,
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);
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);
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);
85 parent.replaceChild(new_cont, cont);
88 function displayDns(data) {
89 let suffixContent = document.getElementById("dns_suffix_content");
90 let suffixParent = suffixContent.parentNode;
93 suffixes = gNetLinkSvc.dnsSuffixList; // May throw
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);
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"));
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);
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);
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;
164 linkType = gNetLinkSvc.linkType;
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
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(
199 perfStatTypes[typeIndex] +
201 perfStatFieldNames[statFieldIndex]
203 data.perfStats[typeIndex][perfStatFieldNames[statFieldIndex]];
208 function displayNetworkID() {
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 =
217 document.getElementById("networkid_id").innerText = networkID;
219 document.getElementById("networkid_isUp").innerText = "<unknown>";
220 document.getElementById("networkid_statusKnown").innerText = "<unknown>";
221 document.getElementById("networkid_id").innerText = "<unknown>";
225 function requestAllNetworkingData() {
226 for (let id in gRequestNetworkingData) {
227 requestNetworkingDataForTab(id);
231 function requestNetworkingDataForTab(id) {
232 gRequestNetworkingData[id](gDashboardCallbacks[id]);
242 requestAllNetworkingData();
244 let autoRefresh = document.getElementById("autorefcheck");
245 if (autoRefresh.checked) {
246 setAutoRefreshInterval(autoRefresh);
249 autoRefresh.addEventListener("click", function () {
250 let refrButton = document.getElementById("refreshButton");
252 setAutoRefreshInterval(this);
253 refrButton.disabled = "disabled";
255 clearInterval(this.interval);
256 refrButton.disabled = null;
260 let refr = document.getElementById("refreshButton");
261 refr.addEventListener("click", requestAllNetworkingData);
262 if (document.getElementById("autorefcheck").checked) {
263 refr.disabled = "disabled";
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) {
274 let dnsLookupButton = document.getElementById("dnsLookupButton");
275 dnsLookupButton.addEventListener("click", function () {
279 let clearDNSCache = document.getElementById("clearDNSCache");
280 clearDNSCache.addEventListener("click", function () {
281 Services.dns.clearCache(true);
285 let sectionButton = document.getElementById(
286 "category-" + location.hash.substring(1)
289 sectionButton.click();
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) {
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);
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 () {
336 function doLookup() {
337 let host = document.getElementById("host").value;
340 gDashboard.requestDNSLookup(host, displayDNSLookup);
343 gDashboard.requestDNSHTTPSRRLookup(host, displayHTTPSRRLookup);
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");
355 for (let address of data.address) {
356 let row = document.createElement("tr");
357 row.appendChild(col(address));
358 new_cont.appendChild(row);
361 new_cont.appendChild(col(data.error));
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");
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}" `
382 let ODoHConfig = record.ODoHConfig
383 ? `odoh="${record.ODoHConfig.ODoHConfig}" `
387 if (record.ipv4Hint) {
389 for (let addr of record.ipv4Hint.address) {
390 ipv4Str += `${addr}, `;
392 // Remove ", " at the end.
393 ipv4Str = ipv4Str.slice(0, -2);
394 ipv4hint = `ipv4hint="${ipv4Str}" `;
396 if (record.ipv6Hint) {
398 for (let addr of record.ipv6Hint.address) {
399 ipv6Str += `${addr}, `;
401 // Remove ", " at the end.
402 ipv6Str = ipv6Str.slice(0, -2);
403 ipv6hint = `ipv6hint="${ipv6Str}" `;
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);
414 new_cont.appendChild(col(data.error));
417 parent.replaceChild(new_cont, cont);