Dashboard.cpp (42844B)
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/. */ 4 5 #include "mozilla/dom/NetDashboardBinding.h" 6 #include "mozilla/dom/ToJSValue.h" 7 #include "mozilla/Components.h" 8 #include "mozilla/ErrorNames.h" 9 #include "mozilla/net/Dashboard.h" 10 #include "mozilla/net/HttpInfo.h" 11 #include "mozilla/net/HTTPSSVC.h" 12 #include "mozilla/net/SocketProcessParent.h" 13 #include "nsHttp.h" 14 #include "nsICancelable.h" 15 #include "nsIDNSListener.h" 16 #include "nsIDNSService.h" 17 #include "nsIDNSRecord.h" 18 #include "nsIDNSByTypeRecord.h" 19 #include "nsIInputStream.h" 20 #include "nsINamed.h" 21 #include "nsINetAddr.h" 22 #include "nsISocketTransport.h" 23 #include "nsProxyRelease.h" 24 #include "nsSocketTransportService2.h" 25 #include "nsThreadUtils.h" 26 #include "nsURLHelper.h" 27 #include "mozilla/Logging.h" 28 #include "nsIOService.h" 29 #include "../cache2/CacheFileUtils.h" 30 31 using mozilla::AutoSafeJSContext; 32 using mozilla::dom::Sequence; 33 using mozilla::dom::ToJSValue; 34 35 namespace mozilla { 36 namespace net { 37 38 class SocketData : public nsISupports { 39 public: 40 NS_DECL_THREADSAFE_ISUPPORTS 41 42 SocketData() = default; 43 44 uint64_t mTotalSent{0}; 45 uint64_t mTotalRecv{0}; 46 nsTArray<SocketInfo> mData; 47 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 48 nsIEventTarget* mEventTarget{nullptr}; 49 50 private: 51 virtual ~SocketData() = default; 52 }; 53 54 static void GetErrorString(nsresult rv, nsAString& errorString); 55 56 NS_IMPL_ISUPPORTS0(SocketData) 57 58 class HttpData : public nsISupports { 59 virtual ~HttpData() = default; 60 61 public: 62 NS_DECL_THREADSAFE_ISUPPORTS 63 64 HttpData() = default; 65 66 nsTArray<HttpRetParams> mData; 67 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 68 nsIEventTarget* mEventTarget{nullptr}; 69 }; 70 71 NS_IMPL_ISUPPORTS0(HttpData) 72 73 class Http3ConnectionStatsData : public nsISupports { 74 virtual ~Http3ConnectionStatsData() = default; 75 76 public: 77 NS_DECL_THREADSAFE_ISUPPORTS 78 79 Http3ConnectionStatsData() = default; 80 81 nsTArray<Http3ConnectionStatsParams> mData; 82 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 83 nsIEventTarget* mEventTarget{nullptr}; 84 }; 85 86 NS_IMPL_ISUPPORTS0(Http3ConnectionStatsData) 87 88 class WebSocketRequest : public nsISupports { 89 virtual ~WebSocketRequest() = default; 90 91 public: 92 NS_DECL_THREADSAFE_ISUPPORTS 93 94 WebSocketRequest() = default; 95 96 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 97 nsIEventTarget* mEventTarget{nullptr}; 98 }; 99 100 NS_IMPL_ISUPPORTS0(WebSocketRequest) 101 102 class DnsData : public nsISupports { 103 virtual ~DnsData() = default; 104 105 public: 106 NS_DECL_THREADSAFE_ISUPPORTS 107 108 DnsData() = default; 109 110 nsTArray<DNSCacheEntries> mData; 111 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 112 nsIEventTarget* mEventTarget{nullptr}; 113 }; 114 115 NS_IMPL_ISUPPORTS0(DnsData) 116 117 class ConnectionData : public nsITransportEventSink, 118 public nsITimerCallback, 119 public nsINamed { 120 virtual ~ConnectionData() { 121 if (mTimer) { 122 mTimer->Cancel(); 123 } 124 } 125 126 public: 127 NS_DECL_THREADSAFE_ISUPPORTS 128 NS_DECL_NSITRANSPORTEVENTSINK 129 NS_DECL_NSITIMERCALLBACK 130 131 NS_IMETHOD GetName(nsACString& aName) override { 132 aName.AssignLiteral("net::ConnectionData"); 133 return NS_OK; 134 } 135 136 void StartTimer(uint32_t aTimeout); 137 void StopTimer(); 138 139 explicit ConnectionData(Dashboard* target) { mDashboard = target; } 140 141 nsCOMPtr<nsISocketTransport> mSocket; 142 nsCOMPtr<nsIInputStream> mStreamIn; 143 nsCOMPtr<nsITimer> mTimer; 144 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 145 nsIEventTarget* mEventTarget{nullptr}; 146 Dashboard* mDashboard; 147 148 nsCString mHost; 149 uint32_t mPort{0}; 150 nsCString mProtocol; 151 uint32_t mTimeout{0}; 152 153 nsString mStatus; 154 }; 155 156 NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback, 157 nsINamed) 158 159 class RcwnData : public nsISupports { 160 virtual ~RcwnData() = default; 161 162 public: 163 NS_DECL_THREADSAFE_ISUPPORTS 164 165 RcwnData() = default; 166 167 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 168 nsIEventTarget* mEventTarget{nullptr}; 169 }; 170 171 NS_IMPL_ISUPPORTS0(RcwnData) 172 173 NS_IMETHODIMP 174 ConnectionData::OnTransportStatus(nsITransport* aTransport, nsresult aStatus, 175 int64_t aProgress, int64_t aProgressMax) { 176 if (aStatus == NS_NET_STATUS_CONNECTED_TO) { 177 StopTimer(); 178 } 179 180 GetErrorString(aStatus, mStatus); 181 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>( 182 "net::Dashboard::GetConnectionStatus", mDashboard, 183 &Dashboard::GetConnectionStatus, this), 184 NS_DISPATCH_NORMAL); 185 186 return NS_OK; 187 } 188 189 NS_IMETHODIMP 190 ConnectionData::Notify(nsITimer* aTimer) { 191 MOZ_ASSERT(aTimer == mTimer); 192 193 if (mSocket) { 194 mSocket->Close(NS_ERROR_ABORT); 195 mSocket = nullptr; 196 mStreamIn = nullptr; 197 } 198 199 mTimer = nullptr; 200 201 mStatus.AssignLiteral(u"NS_ERROR_NET_TIMEOUT"); 202 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>( 203 "net::Dashboard::GetConnectionStatus", mDashboard, 204 &Dashboard::GetConnectionStatus, this), 205 NS_DISPATCH_NORMAL); 206 207 return NS_OK; 208 } 209 210 void ConnectionData::StartTimer(uint32_t aTimeout) { 211 if (!mTimer) { 212 mTimer = NS_NewTimer(); 213 } 214 215 mTimer->InitWithCallback(this, aTimeout * 1000, nsITimer::TYPE_ONE_SHOT); 216 } 217 218 void ConnectionData::StopTimer() { 219 if (mTimer) { 220 mTimer->Cancel(); 221 mTimer = nullptr; 222 } 223 } 224 225 class LookupHelper; 226 227 class LookupArgument : public nsISupports { 228 virtual ~LookupArgument() = default; 229 230 public: 231 NS_DECL_THREADSAFE_ISUPPORTS 232 233 LookupArgument(nsIDNSRecord* aRecord, LookupHelper* aHelper) { 234 mRecord = aRecord; 235 mHelper = aHelper; 236 } 237 238 nsCOMPtr<nsIDNSRecord> mRecord; 239 RefPtr<LookupHelper> mHelper; 240 }; 241 242 NS_IMPL_ISUPPORTS0(LookupArgument) 243 244 class LookupHelper final : public nsIDNSListener { 245 virtual ~LookupHelper() { 246 if (mCancel) { 247 mCancel->Cancel(NS_ERROR_ABORT); 248 } 249 } 250 251 public: 252 NS_DECL_THREADSAFE_ISUPPORTS 253 NS_DECL_NSIDNSLISTENER 254 255 LookupHelper() = default; 256 257 nsresult ConstructAnswer(LookupArgument* aArgument); 258 nsresult ConstructHTTPSRRAnswer(LookupArgument* aArgument); 259 260 public: 261 nsCOMPtr<nsICancelable> mCancel; 262 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback; 263 nsIEventTarget* mEventTarget{nullptr}; 264 nsresult mStatus{NS_ERROR_NOT_INITIALIZED}; 265 }; 266 267 NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener) 268 269 NS_IMETHODIMP 270 LookupHelper::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRecord, 271 nsresult aStatus) { 272 MOZ_ASSERT(aRequest == mCancel); 273 mCancel = nullptr; 274 mStatus = aStatus; 275 276 nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord = do_QueryInterface(aRecord); 277 if (httpsRecord) { 278 RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this); 279 mEventTarget->Dispatch( 280 NewRunnableMethod<RefPtr<LookupArgument>>( 281 "net::LookupHelper::ConstructHTTPSRRAnswer", this, 282 &LookupHelper::ConstructHTTPSRRAnswer, arg), 283 NS_DISPATCH_NORMAL); 284 return NS_OK; 285 } 286 287 RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this); 288 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<LookupArgument>>( 289 "net::LookupHelper::ConstructAnswer", this, 290 &LookupHelper::ConstructAnswer, arg), 291 NS_DISPATCH_NORMAL); 292 293 return NS_OK; 294 } 295 296 nsresult LookupHelper::ConstructAnswer(LookupArgument* aArgument) { 297 nsIDNSRecord* aRecord = aArgument->mRecord; 298 AutoSafeJSContext cx; 299 300 mozilla::dom::DNSLookupDict dict; 301 dict.mAddress.Construct(); 302 303 Sequence<nsString>& addresses = dict.mAddress.Value(); 304 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(aRecord); 305 if (NS_SUCCEEDED(mStatus) && record) { 306 dict.mAnswer = true; 307 bool hasMore; 308 record->HasMore(&hasMore); 309 while (hasMore) { 310 nsString* nextAddress = addresses.AppendElement(fallible); 311 if (!nextAddress) { 312 return NS_ERROR_OUT_OF_MEMORY; 313 } 314 315 nsCString nextAddressASCII; 316 record->GetNextAddrAsString(nextAddressASCII); 317 CopyASCIItoUTF16(nextAddressASCII, *nextAddress); 318 record->HasMore(&hasMore); 319 } 320 } else { 321 dict.mAnswer = false; 322 GetErrorString(mStatus, dict.mError); 323 } 324 325 JS::Rooted<JS::Value> val(cx); 326 if (!ToJSValue(cx, dict, &val)) { 327 return NS_ERROR_FAILURE; 328 } 329 330 this->mCallback->OnDashboardDataAvailable(val); 331 332 return NS_OK; 333 } 334 335 static void CStringToHexString(const nsACString& aIn, nsAString& aOut) { 336 static const char* const lut = "0123456789ABCDEF"; 337 338 size_t len = aIn.Length(); 339 340 aOut.SetCapacity(2 * len); 341 for (size_t i = 0; i < aIn.Length(); ++i) { 342 const char c = static_cast<char>(aIn[i]); 343 aOut.Append(lut[(c >> 4) & 0x0F]); 344 aOut.Append(lut[c & 15]); 345 } 346 } 347 348 nsresult LookupHelper::ConstructHTTPSRRAnswer(LookupArgument* aArgument) { 349 nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord = 350 do_QueryInterface(aArgument->mRecord); 351 352 AutoSafeJSContext cx; 353 354 mozilla::dom::HTTPSRRLookupDict dict; 355 dict.mRecords.Construct(); 356 357 Sequence<dom::HTTPSRecord>& records = dict.mRecords.Value(); 358 if (NS_SUCCEEDED(mStatus) && httpsRecord) { 359 dict.mAnswer = true; 360 nsTArray<RefPtr<nsISVCBRecord>> svcbRecords; 361 httpsRecord->GetRecords(svcbRecords); 362 363 for (const auto& record : svcbRecords) { 364 dom::HTTPSRecord* nextRecord = records.AppendElement(fallible); 365 if (!nextRecord) { 366 return NS_ERROR_OUT_OF_MEMORY; 367 } 368 369 (void)record->GetPriority(&nextRecord->mPriority); 370 nsCString name; 371 (void)record->GetName(name); 372 CopyASCIItoUTF16(name, nextRecord->mTargetName); 373 374 nsTArray<RefPtr<nsISVCParam>> values; 375 (void)record->GetValues(values); 376 if (values.IsEmpty()) { 377 continue; 378 } 379 380 for (const auto& value : values) { 381 uint16_t type; 382 (void)value->GetType(&type); 383 switch (type) { 384 case SvcParamKeyAlpn: { 385 nextRecord->mAlpn.Construct(); 386 nextRecord->mAlpn.Value().mType = type; 387 nsCOMPtr<nsISVCParamAlpn> alpnParam = do_QueryInterface(value); 388 nsTArray<nsCString> alpn; 389 (void)alpnParam->GetAlpn(alpn); 390 nsAutoCString alpnStr; 391 for (const auto& str : alpn) { 392 alpnStr.Append(str); 393 alpnStr.Append(','); 394 } 395 CopyASCIItoUTF16(Span(alpnStr.BeginReading(), alpnStr.Length() - 1), 396 nextRecord->mAlpn.Value().mAlpn); 397 break; 398 } 399 case SvcParamKeyNoDefaultAlpn: { 400 nextRecord->mNoDefaultAlpn.Construct(); 401 nextRecord->mNoDefaultAlpn.Value().mType = type; 402 break; 403 } 404 case SvcParamKeyPort: { 405 nextRecord->mPort.Construct(); 406 nextRecord->mPort.Value().mType = type; 407 nsCOMPtr<nsISVCParamPort> portParam = do_QueryInterface(value); 408 (void)portParam->GetPort(&nextRecord->mPort.Value().mPort); 409 break; 410 } 411 case SvcParamKeyIpv4Hint: { 412 nextRecord->mIpv4Hint.Construct(); 413 nextRecord->mIpv4Hint.Value().mType = type; 414 nsCOMPtr<nsISVCParamIPv4Hint> ipv4Param = do_QueryInterface(value); 415 nsTArray<RefPtr<nsINetAddr>> ipv4Hint; 416 (void)ipv4Param->GetIpv4Hint(ipv4Hint); 417 if (!ipv4Hint.IsEmpty()) { 418 nextRecord->mIpv4Hint.Value().mAddress.Construct(); 419 for (const auto& address : ipv4Hint) { 420 nsString* nextAddress = nextRecord->mIpv4Hint.Value() 421 .mAddress.Value() 422 .AppendElement(fallible); 423 if (!nextAddress) { 424 return NS_ERROR_OUT_OF_MEMORY; 425 } 426 427 nsCString addressASCII; 428 (void)address->GetAddress(addressASCII); 429 CopyASCIItoUTF16(addressASCII, *nextAddress); 430 } 431 } 432 break; 433 } 434 case SvcParamKeyIpv6Hint: { 435 nextRecord->mIpv6Hint.Construct(); 436 nextRecord->mIpv6Hint.Value().mType = type; 437 nsCOMPtr<nsISVCParamIPv6Hint> ipv6Param = do_QueryInterface(value); 438 nsTArray<RefPtr<nsINetAddr>> ipv6Hint; 439 (void)ipv6Param->GetIpv6Hint(ipv6Hint); 440 if (!ipv6Hint.IsEmpty()) { 441 nextRecord->mIpv6Hint.Value().mAddress.Construct(); 442 for (const auto& address : ipv6Hint) { 443 nsString* nextAddress = nextRecord->mIpv6Hint.Value() 444 .mAddress.Value() 445 .AppendElement(fallible); 446 if (!nextAddress) { 447 return NS_ERROR_OUT_OF_MEMORY; 448 } 449 450 nsCString addressASCII; 451 (void)address->GetAddress(addressASCII); 452 CopyASCIItoUTF16(addressASCII, *nextAddress); 453 } 454 } 455 break; 456 } 457 case SvcParamKeyEchConfig: { 458 nextRecord->mEchConfig.Construct(); 459 nextRecord->mEchConfig.Value().mType = type; 460 nsCOMPtr<nsISVCParamEchConfig> echConfigParam = 461 do_QueryInterface(value); 462 nsCString echConfigStr; 463 (void)echConfigParam->GetEchconfig(echConfigStr); 464 CStringToHexString(echConfigStr, 465 nextRecord->mEchConfig.Value().mEchConfig); 466 break; 467 } 468 case SvcParamKeyODoHConfig: { 469 nextRecord->mODoHConfig.Construct(); 470 nextRecord->mODoHConfig.Value().mType = type; 471 nsCOMPtr<nsISVCParamODoHConfig> ODoHConfigParam = 472 do_QueryInterface(value); 473 nsCString ODoHConfigStr; 474 (void)ODoHConfigParam->GetODoHConfig(ODoHConfigStr); 475 CStringToHexString(ODoHConfigStr, 476 nextRecord->mODoHConfig.Value().mODoHConfig); 477 break; 478 } 479 default: 480 break; 481 } 482 } 483 } 484 } else { 485 dict.mAnswer = false; 486 GetErrorString(mStatus, dict.mError); 487 } 488 489 JS::Rooted<JS::Value> val(cx); 490 if (!ToJSValue(cx, dict, &val)) { 491 return NS_ERROR_FAILURE; 492 } 493 494 this->mCallback->OnDashboardDataAvailable(val); 495 496 return NS_OK; 497 } 498 499 NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier) 500 501 Dashboard::Dashboard() { mEnableLogging = false; } 502 503 NS_IMETHODIMP 504 Dashboard::RequestSockets(nsINetDashboardCallback* aCallback) { 505 RefPtr<SocketData> socketData = new SocketData(); 506 socketData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 507 "nsINetDashboardCallback", aCallback, true); 508 socketData->mEventTarget = GetCurrentSerialEventTarget(); 509 510 if (nsIOService::UseSocketProcess()) { 511 if (!gIOService->SocketProcessReady()) { 512 return NS_ERROR_NOT_AVAILABLE; 513 } 514 515 RefPtr<Dashboard> self(this); 516 RefPtr<SocketProcessParent> socketParent = 517 SocketProcessParent::GetSingleton(); 518 socketParent->SendGetSocketData()->Then( 519 GetMainThreadSerialEventTarget(), __func__, 520 [self{std::move(self)}, 521 socketData{std::move(socketData)}](SocketDataArgs&& args) { 522 socketData->mData.Assign(args.info()); 523 socketData->mTotalSent = args.totalSent(); 524 socketData->mTotalRecv = args.totalRecv(); 525 socketData->mEventTarget->Dispatch( 526 NewRunnableMethod<RefPtr<SocketData>>( 527 "net::Dashboard::GetSockets", self, &Dashboard::GetSockets, 528 socketData), 529 NS_DISPATCH_NORMAL); 530 }, 531 [self](const mozilla::ipc::ResponseRejectReason) {}); 532 return NS_OK; 533 } 534 535 gSocketTransportService->Dispatch( 536 NewRunnableMethod<RefPtr<SocketData>>( 537 "net::Dashboard::GetSocketsDispatch", this, 538 &Dashboard::GetSocketsDispatch, socketData), 539 NS_DISPATCH_NORMAL); 540 return NS_OK; 541 } 542 543 nsresult Dashboard::GetSocketsDispatch(SocketData* aSocketData) { 544 RefPtr<SocketData> socketData = aSocketData; 545 if (gSocketTransportService) { 546 gSocketTransportService->GetSocketConnections(&socketData->mData); 547 socketData->mTotalSent = gSocketTransportService->GetSentBytes(); 548 socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes(); 549 } 550 socketData->mEventTarget->Dispatch( 551 NewRunnableMethod<RefPtr<SocketData>>("net::Dashboard::GetSockets", this, 552 &Dashboard::GetSockets, socketData), 553 NS_DISPATCH_NORMAL); 554 return NS_OK; 555 } 556 557 nsresult Dashboard::GetSockets(SocketData* aSocketData) { 558 RefPtr<SocketData> socketData = aSocketData; 559 AutoSafeJSContext cx; 560 561 mozilla::dom::SocketsDict dict; 562 dict.mSockets.Construct(); 563 dict.mSent = 0; 564 dict.mReceived = 0; 565 566 Sequence<mozilla::dom::SocketElement>& sockets = dict.mSockets.Value(); 567 568 uint32_t length = socketData->mData.Length(); 569 if (!sockets.SetCapacity(length, fallible)) { 570 JS_ReportOutOfMemory(cx); 571 return NS_ERROR_OUT_OF_MEMORY; 572 } 573 574 for (uint32_t i = 0; i < socketData->mData.Length(); i++) { 575 dom::SocketElement& mSocket = *sockets.AppendElement(fallible); 576 CopyASCIItoUTF16(socketData->mData[i].host, mSocket.mHost); 577 mSocket.mPort = socketData->mData[i].port; 578 mSocket.mActive = socketData->mData[i].active; 579 CopyASCIItoUTF16(socketData->mData[i].type, mSocket.mType); 580 mSocket.mSent = (double)socketData->mData[i].sent; 581 mSocket.mReceived = (double)socketData->mData[i].received; 582 dict.mSent += socketData->mData[i].sent; 583 dict.mReceived += socketData->mData[i].received; 584 } 585 586 dict.mSent += socketData->mTotalSent; 587 dict.mReceived += socketData->mTotalRecv; 588 JS::Rooted<JS::Value> val(cx); 589 if (!ToJSValue(cx, dict, &val)) return NS_ERROR_FAILURE; 590 socketData->mCallback->OnDashboardDataAvailable(val); 591 592 return NS_OK; 593 } 594 595 NS_IMETHODIMP 596 Dashboard::RequestHttpConnections(nsINetDashboardCallback* aCallback) { 597 RefPtr<HttpData> httpData = new HttpData(); 598 httpData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 599 "nsINetDashboardCallback", aCallback, true); 600 httpData->mEventTarget = GetCurrentSerialEventTarget(); 601 602 if (nsIOService::UseSocketProcess()) { 603 if (!gIOService->SocketProcessReady()) { 604 return NS_ERROR_NOT_AVAILABLE; 605 } 606 607 RefPtr<Dashboard> self(this); 608 RefPtr<SocketProcessParent> socketParent = 609 SocketProcessParent::GetSingleton(); 610 socketParent->SendGetHttpConnectionData()->Then( 611 GetMainThreadSerialEventTarget(), __func__, 612 [self{std::move(self)}, httpData](nsTArray<HttpRetParams>&& params) { 613 httpData->mData.Assign(std::move(params)); 614 self->GetHttpConnections(httpData); 615 httpData->mEventTarget->Dispatch( 616 NewRunnableMethod<RefPtr<HttpData>>( 617 "net::Dashboard::GetHttpConnections", self, 618 &Dashboard::GetHttpConnections, httpData), 619 NS_DISPATCH_NORMAL); 620 }, 621 [self](const mozilla::ipc::ResponseRejectReason) {}); 622 return NS_OK; 623 } 624 625 gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<HttpData>>( 626 "net::Dashboard::GetHttpDispatch", this, 627 &Dashboard::GetHttpDispatch, httpData), 628 NS_DISPATCH_NORMAL); 629 return NS_OK; 630 } 631 632 nsresult Dashboard::GetHttpDispatch(HttpData* aHttpData) { 633 RefPtr<HttpData> httpData = aHttpData; 634 HttpInfo::GetHttpConnectionData(&httpData->mData); 635 httpData->mEventTarget->Dispatch( 636 NewRunnableMethod<RefPtr<HttpData>>("net::Dashboard::GetHttpConnections", 637 this, &Dashboard::GetHttpConnections, 638 httpData), 639 NS_DISPATCH_NORMAL); 640 return NS_OK; 641 } 642 643 nsresult Dashboard::GetHttpConnections(HttpData* aHttpData) { 644 RefPtr<HttpData> httpData = aHttpData; 645 AutoSafeJSContext cx; 646 647 mozilla::dom::HttpConnDict dict; 648 dict.mConnections.Construct(); 649 650 using mozilla::dom::DnsAndSockInfoDict; 651 using mozilla::dom::HttpConnectionElement; 652 using mozilla::dom::HttpConnInfo; 653 Sequence<HttpConnectionElement>& connections = dict.mConnections.Value(); 654 655 uint32_t length = httpData->mData.Length(); 656 if (!connections.SetCapacity(length, fallible)) { 657 JS_ReportOutOfMemory(cx); 658 return NS_ERROR_OUT_OF_MEMORY; 659 } 660 661 for (uint32_t i = 0; i < httpData->mData.Length(); i++) { 662 HttpConnectionElement& connection = *connections.AppendElement(fallible); 663 664 CopyASCIItoUTF16(httpData->mData[i].host, connection.mHost); 665 connection.mPort = httpData->mData[i].port; 666 CopyASCIItoUTF16(httpData->mData[i].httpVersion, connection.mHttpVersion); 667 connection.mSsl = httpData->mData[i].ssl; 668 669 connection.mActive.Construct(); 670 connection.mIdle.Construct(); 671 connection.mDnsAndSocks.Construct(); 672 673 Sequence<HttpConnInfo>& active = connection.mActive.Value(); 674 Sequence<HttpConnInfo>& idle = connection.mIdle.Value(); 675 Sequence<DnsAndSockInfoDict>& dnsAndSocks = connection.mDnsAndSocks.Value(); 676 677 if (!active.SetCapacity(httpData->mData[i].active.Length(), fallible) || 678 !idle.SetCapacity(httpData->mData[i].idle.Length(), fallible) || 679 !dnsAndSocks.SetCapacity(httpData->mData[i].dnsAndSocks.Length(), 680 fallible)) { 681 JS_ReportOutOfMemory(cx); 682 return NS_ERROR_OUT_OF_MEMORY; 683 } 684 685 for (uint32_t j = 0; j < httpData->mData[i].active.Length(); j++) { 686 HttpConnInfo& info = *active.AppendElement(fallible); 687 info.mRtt = httpData->mData[i].active[j].rtt; 688 info.mTtl = httpData->mData[i].active[j].ttl; 689 info.mProtocolVersion = httpData->mData[i].active[j].protocolVersion; 690 } 691 692 for (uint32_t j = 0; j < httpData->mData[i].idle.Length(); j++) { 693 HttpConnInfo& info = *idle.AppendElement(fallible); 694 info.mRtt = httpData->mData[i].idle[j].rtt; 695 info.mTtl = httpData->mData[i].idle[j].ttl; 696 info.mProtocolVersion = httpData->mData[i].idle[j].protocolVersion; 697 } 698 699 for (uint32_t j = 0; j < httpData->mData[i].dnsAndSocks.Length(); j++) { 700 DnsAndSockInfoDict& info = *dnsAndSocks.AppendElement(fallible); 701 info.mSpeculative = httpData->mData[i].dnsAndSocks[j].speculative; 702 } 703 } 704 705 JS::Rooted<JS::Value> val(cx); 706 if (!ToJSValue(cx, dict, &val)) { 707 return NS_ERROR_FAILURE; 708 } 709 710 httpData->mCallback->OnDashboardDataAvailable(val); 711 712 return NS_OK; 713 } 714 715 NS_IMETHODIMP 716 Dashboard::RequestHttp3ConnectionStats(nsINetDashboardCallback* aCallback) { 717 RefPtr<Http3ConnectionStatsData> data = new Http3ConnectionStatsData(); 718 data->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 719 "nsINetDashboardCallback", aCallback, true); 720 data->mEventTarget = GetCurrentSerialEventTarget(); 721 722 if (nsIOService::UseSocketProcess()) { 723 if (!gIOService->SocketProcessReady()) { 724 return NS_ERROR_NOT_AVAILABLE; 725 } 726 727 RefPtr<Dashboard> self(this); 728 RefPtr<SocketProcessParent> socketParent = 729 SocketProcessParent::GetSingleton(); 730 socketParent->SendGetHttp3ConnectionStatsData()->Then( 731 GetMainThreadSerialEventTarget(), __func__, 732 [self{std::move(self)}, 733 data](nsTArray<Http3ConnectionStatsParams>&& params) { 734 data->mData.Assign(std::move(params)); 735 self->GetHttp3ConnectionStats(data); 736 data->mEventTarget->Dispatch( 737 NewRunnableMethod<RefPtr<Http3ConnectionStatsData>>( 738 "net::Dashboard::GetHttp3ConnectionStats", self, 739 &Dashboard::GetHttp3ConnectionStats, data), 740 NS_DISPATCH_NORMAL); 741 }, 742 [self](const mozilla::ipc::ResponseRejectReason) {}); 743 return NS_OK; 744 } 745 746 gSocketTransportService->Dispatch( 747 NewRunnableMethod<RefPtr<Http3ConnectionStatsData>>( 748 "net::Dashboard::GetHttp3ConnectionStatsDispatch", this, 749 &Dashboard::GetHttp3ConnectionStatsDispatch, data), 750 NS_DISPATCH_NORMAL); 751 return NS_OK; 752 } 753 754 nsresult Dashboard::GetHttp3ConnectionStatsDispatch( 755 Http3ConnectionStatsData* aData) { 756 RefPtr<Http3ConnectionStatsData> data = aData; 757 HttpInfo::GetHttp3ConnectionStatsData(&data->mData); 758 data->mEventTarget->Dispatch( 759 NewRunnableMethod<RefPtr<Http3ConnectionStatsData>>( 760 "net::Dashboard::GetHttp3ConnectionStats", this, 761 &Dashboard::GetHttp3ConnectionStats, data), 762 NS_DISPATCH_NORMAL); 763 return NS_OK; 764 } 765 766 nsresult Dashboard::GetHttp3ConnectionStats(Http3ConnectionStatsData* aData) { 767 RefPtr<Http3ConnectionStatsData> data = aData; 768 AutoSafeJSContext cx; 769 770 mozilla::dom::Http3ConnStatsDict dict; 771 dict.mConnections.Construct(); 772 773 using mozilla::dom::Http3ConnectionStatsElement; 774 using mozilla::dom::Http3ConnStats; 775 Sequence<Http3ConnectionStatsElement>& connections = 776 dict.mConnections.Value(); 777 778 uint32_t length = data->mData.Length(); 779 if (!connections.SetCapacity(length, fallible)) { 780 JS_ReportOutOfMemory(cx); 781 return NS_ERROR_OUT_OF_MEMORY; 782 } 783 784 for (uint32_t i = 0; i < data->mData.Length(); i++) { 785 Http3ConnectionStatsElement& connection = 786 *connections.AppendElement(fallible); 787 788 CopyASCIItoUTF16(data->mData[i].host, connection.mHost); 789 connection.mPort = data->mData[i].port; 790 791 connection.mStats.Construct(); 792 793 Sequence<Http3ConnStats>& stats = connection.mStats.Value(); 794 795 if (!stats.SetCapacity(data->mData[i].stats.Length(), fallible)) { 796 JS_ReportOutOfMemory(cx); 797 return NS_ERROR_OUT_OF_MEMORY; 798 } 799 800 for (uint32_t j = 0; j < data->mData[i].stats.Length(); j++) { 801 Http3ConnStats& info = *stats.AppendElement(fallible); 802 info.mPacketsRx = data->mData[i].stats[j].packetsRx; 803 info.mDupsRx = data->mData[i].stats[j].dupsRx; 804 info.mDroppedRx = data->mData[i].stats[j].droppedRx; 805 info.mSavedDatagrams = data->mData[i].stats[j].savedDatagrams; 806 info.mPacketsTx = data->mData[i].stats[j].packetsTx; 807 info.mLost = data->mData[i].stats[j].lost; 808 info.mLateAck = data->mData[i].stats[j].lateAck; 809 info.mPtoAck = data->mData[i].stats[j].ptoAck; 810 info.mWouldBlockRx = data->mData[i].stats[j].wouldBlockRx; 811 info.mWouldBlockTx = data->mData[i].stats[j].wouldBlockTx; 812 info.mPtoCounts.Construct(); 813 Sequence<uint64_t>& ptoCounts = info.mPtoCounts.Value(); 814 if (!ptoCounts.SetCapacity(data->mData[i].stats[j].ptoCounts.Length(), 815 fallible)) { 816 JS_ReportOutOfMemory(cx); 817 return NS_ERROR_OUT_OF_MEMORY; 818 } 819 for (auto pto : data->mData[i].stats[j].ptoCounts) { 820 uint64_t& element = *ptoCounts.AppendElement(fallible); 821 element = pto; 822 } 823 } 824 } 825 826 JS::Rooted<JS::Value> val(cx); 827 if (!ToJSValue(cx, dict, &val)) { 828 return NS_ERROR_FAILURE; 829 } 830 831 data->mCallback->OnDashboardDataAvailable(val); 832 833 return NS_OK; 834 } 835 836 NS_IMETHODIMP 837 Dashboard::GetEnableLogging(bool* value) { 838 *value = mEnableLogging; 839 return NS_OK; 840 } 841 842 NS_IMETHODIMP 843 Dashboard::SetEnableLogging(const bool value) { 844 mEnableLogging = value; 845 return NS_OK; 846 } 847 848 NS_IMETHODIMP 849 Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted) { 850 if (mEnableLogging) { 851 mozilla::MutexAutoLock lock(mWs.lock); 852 LogData mData(nsCString(aHost), aSerial, aEncrypted); 853 if (mWs.data.Contains(mData)) { 854 return NS_OK; 855 } 856 // XXX(Bug 1631371) Check if this should use a fallible operation as it 857 // pretended earlier. 858 mWs.data.AppendElement(mData); 859 return NS_OK; 860 } 861 return NS_ERROR_FAILURE; 862 } 863 864 NS_IMETHODIMP 865 Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial) { 866 if (mEnableLogging) { 867 mozilla::MutexAutoLock lock(mWs.lock); 868 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); 869 if (index == -1) return NS_ERROR_FAILURE; 870 mWs.data.RemoveElementAt(index); 871 return NS_OK; 872 } 873 return NS_ERROR_FAILURE; 874 } 875 876 NS_IMETHODIMP 877 Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, 878 uint32_t aLength) { 879 if (mEnableLogging) { 880 mozilla::MutexAutoLock lock(mWs.lock); 881 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); 882 if (index == -1) return NS_ERROR_FAILURE; 883 mWs.data[index].mMsgSent++; 884 mWs.data[index].mSizeSent += aLength; 885 return NS_OK; 886 } 887 return NS_ERROR_FAILURE; 888 } 889 890 NS_IMETHODIMP 891 Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, 892 uint32_t aLength) { 893 if (mEnableLogging) { 894 mozilla::MutexAutoLock lock(mWs.lock); 895 int32_t index = mWs.IndexOf(nsCString(aHost), aSerial); 896 if (index == -1) return NS_ERROR_FAILURE; 897 mWs.data[index].mMsgReceived++; 898 mWs.data[index].mSizeReceived += aLength; 899 return NS_OK; 900 } 901 return NS_ERROR_FAILURE; 902 } 903 904 NS_IMETHODIMP 905 Dashboard::RequestWebsocketConnections(nsINetDashboardCallback* aCallback) { 906 RefPtr<WebSocketRequest> wsRequest = new WebSocketRequest(); 907 wsRequest->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 908 "nsINetDashboardCallback", aCallback, true); 909 wsRequest->mEventTarget = GetCurrentSerialEventTarget(); 910 911 wsRequest->mEventTarget->Dispatch( 912 NewRunnableMethod<RefPtr<WebSocketRequest>>( 913 "net::Dashboard::GetWebSocketConnections", this, 914 &Dashboard::GetWebSocketConnections, wsRequest), 915 NS_DISPATCH_NORMAL); 916 return NS_OK; 917 } 918 919 nsresult Dashboard::GetWebSocketConnections(WebSocketRequest* aWsRequest) { 920 RefPtr<WebSocketRequest> wsRequest = aWsRequest; 921 AutoSafeJSContext cx; 922 923 mozilla::dom::WebSocketDict dict; 924 dict.mWebsockets.Construct(); 925 Sequence<mozilla::dom::WebSocketElement>& websockets = 926 dict.mWebsockets.Value(); 927 928 mozilla::MutexAutoLock lock(mWs.lock); 929 uint32_t length = mWs.data.Length(); 930 if (!websockets.SetCapacity(length, fallible)) { 931 JS_ReportOutOfMemory(cx); 932 return NS_ERROR_OUT_OF_MEMORY; 933 } 934 935 for (uint32_t i = 0; i < mWs.data.Length(); i++) { 936 dom::WebSocketElement& websocket = *websockets.AppendElement(fallible); 937 CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport); 938 websocket.mMsgsent = mWs.data[i].mMsgSent; 939 websocket.mMsgreceived = mWs.data[i].mMsgReceived; 940 websocket.mSentsize = mWs.data[i].mSizeSent; 941 websocket.mReceivedsize = mWs.data[i].mSizeReceived; 942 websocket.mEncrypted = mWs.data[i].mEncrypted; 943 } 944 945 JS::Rooted<JS::Value> val(cx); 946 if (!ToJSValue(cx, dict, &val)) { 947 return NS_ERROR_FAILURE; 948 } 949 wsRequest->mCallback->OnDashboardDataAvailable(val); 950 951 return NS_OK; 952 } 953 954 NS_IMETHODIMP 955 Dashboard::RequestDNSInfo(nsINetDashboardCallback* aCallback) { 956 RefPtr<DnsData> dnsData = new DnsData(); 957 dnsData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 958 "nsINetDashboardCallback", aCallback, true); 959 960 nsresult rv; 961 dnsData->mData.Clear(); 962 dnsData->mEventTarget = GetCurrentSerialEventTarget(); 963 964 if (!mDnsService) { 965 mDnsService = mozilla::components::DNS::Service(&rv); 966 if (NS_FAILED(rv)) { 967 return rv; 968 } 969 } 970 971 if (nsIOService::UseSocketProcess()) { 972 if (!gIOService->SocketProcessReady()) { 973 return NS_ERROR_NOT_AVAILABLE; 974 } 975 976 RefPtr<Dashboard> self(this); 977 RefPtr<SocketProcessParent> socketParent = 978 SocketProcessParent::GetSingleton(); 979 socketParent->SendGetDNSCacheEntries()->Then( 980 GetMainThreadSerialEventTarget(), __func__, 981 [self{std::move(self)}, 982 dnsData{std::move(dnsData)}](nsTArray<DNSCacheEntries>&& entries) { 983 dnsData->mData.Assign(std::move(entries)); 984 dnsData->mEventTarget->Dispatch( 985 NewRunnableMethod<RefPtr<DnsData>>( 986 "net::Dashboard::GetDNSCacheEntries", self, 987 &Dashboard::GetDNSCacheEntries, dnsData), 988 NS_DISPATCH_NORMAL); 989 }, 990 [self](const mozilla::ipc::ResponseRejectReason) {}); 991 return NS_OK; 992 } 993 994 gSocketTransportService->Dispatch( 995 NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDnsInfoDispatch", 996 this, &Dashboard::GetDnsInfoDispatch, 997 dnsData), 998 NS_DISPATCH_NORMAL); 999 return NS_OK; 1000 } 1001 1002 nsresult Dashboard::GetDnsInfoDispatch(DnsData* aDnsData) { 1003 RefPtr<DnsData> dnsData = aDnsData; 1004 if (mDnsService) { 1005 mDnsService->GetDNSCacheEntries(&dnsData->mData); 1006 } 1007 dnsData->mEventTarget->Dispatch( 1008 NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDNSCacheEntries", 1009 this, &Dashboard::GetDNSCacheEntries, 1010 dnsData), 1011 NS_DISPATCH_NORMAL); 1012 return NS_OK; 1013 } 1014 1015 nsresult Dashboard::GetDNSCacheEntries(DnsData* dnsData) { 1016 AutoSafeJSContext cx; 1017 1018 mozilla::dom::DNSCacheDict dict; 1019 dict.mEntries.Construct(); 1020 Sequence<mozilla::dom::DnsCacheEntry>& entries = dict.mEntries.Value(); 1021 1022 uint32_t length = dnsData->mData.Length(); 1023 if (!entries.SetCapacity(length, fallible)) { 1024 JS_ReportOutOfMemory(cx); 1025 return NS_ERROR_OUT_OF_MEMORY; 1026 } 1027 1028 for (uint32_t i = 0; i < dnsData->mData.Length(); i++) { 1029 dom::DnsCacheEntry& entry = *entries.AppendElement(fallible); 1030 entry.mHostaddr.Construct(); 1031 1032 Sequence<nsString>& addrs = entry.mHostaddr.Value(); 1033 if (!addrs.SetCapacity(dnsData->mData[i].hostaddr.Length(), fallible)) { 1034 JS_ReportOutOfMemory(cx); 1035 return NS_ERROR_OUT_OF_MEMORY; 1036 } 1037 1038 CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname); 1039 entry.mExpiration = dnsData->mData[i].expiration; 1040 entry.mTrr = dnsData->mData[i].TRR; 1041 1042 for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) { 1043 nsString* addr = addrs.AppendElement(fallible); 1044 if (!addr) { 1045 JS_ReportOutOfMemory(cx); 1046 return NS_ERROR_OUT_OF_MEMORY; 1047 } 1048 CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], *addr); 1049 } 1050 1051 entry.mType = dnsData->mData[i].resolveType; 1052 if (entry.mType == nsIDNSService::RESOLVE_TYPE_DEFAULT) { 1053 if (dnsData->mData[i].family == PR_AF_INET6) { 1054 entry.mFamily.AssignLiteral(u"ipv6"); 1055 } else { 1056 entry.mFamily.AssignLiteral(u"ipv4"); 1057 } 1058 } 1059 1060 entry.mOriginAttributesSuffix = 1061 NS_ConvertUTF8toUTF16(dnsData->mData[i].originAttributesSuffix); 1062 entry.mFlags = NS_ConvertUTF8toUTF16(dnsData->mData[i].flags); 1063 } 1064 1065 JS::Rooted<JS::Value> val(cx); 1066 if (!ToJSValue(cx, dict, &val)) { 1067 return NS_ERROR_FAILURE; 1068 } 1069 dnsData->mCallback->OnDashboardDataAvailable(val); 1070 1071 return NS_OK; 1072 } 1073 1074 NS_IMETHODIMP 1075 Dashboard::RequestDNSLookup(const nsACString& aHost, 1076 nsINetDashboardCallback* aCallback) { 1077 nsresult rv; 1078 1079 if (!mDnsService) { 1080 mDnsService = mozilla::components::DNS::Service(&rv); 1081 if (NS_FAILED(rv)) { 1082 return rv; 1083 } 1084 } 1085 1086 RefPtr<LookupHelper> helper = new LookupHelper(); 1087 helper->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 1088 "nsINetDashboardCallback", aCallback, true); 1089 helper->mEventTarget = GetCurrentSerialEventTarget(); 1090 OriginAttributes attrs; 1091 rv = mDnsService->AsyncResolveNative( 1092 aHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, 1093 nsIDNSService::RESOLVE_DEFAULT_FLAGS, nullptr, helper.get(), 1094 NS_GetCurrentThread(), attrs, getter_AddRefs(helper->mCancel)); 1095 return rv; 1096 } 1097 1098 NS_IMETHODIMP 1099 Dashboard::RequestDNSHTTPSRRLookup(const nsACString& aHost, 1100 nsINetDashboardCallback* aCallback) { 1101 nsresult rv; 1102 1103 if (!mDnsService) { 1104 mDnsService = mozilla::components::DNS::Service(&rv); 1105 if (NS_FAILED(rv)) { 1106 return rv; 1107 } 1108 } 1109 1110 RefPtr<LookupHelper> helper = new LookupHelper(); 1111 helper->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 1112 "nsINetDashboardCallback", aCallback, true); 1113 helper->mEventTarget = GetCurrentSerialEventTarget(); 1114 OriginAttributes attrs; 1115 rv = mDnsService->AsyncResolveNative( 1116 aHost, nsIDNSService::RESOLVE_TYPE_HTTPSSVC, 1117 nsIDNSService::RESOLVE_DEFAULT_FLAGS, nullptr, helper.get(), 1118 NS_GetCurrentThread(), attrs, getter_AddRefs(helper->mCancel)); 1119 return rv; 1120 } 1121 1122 NS_IMETHODIMP 1123 Dashboard::RequestRcwnStats(nsINetDashboardCallback* aCallback) { 1124 RefPtr<RcwnData> rcwnData = new RcwnData(); 1125 rcwnData->mEventTarget = GetCurrentSerialEventTarget(); 1126 rcwnData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>( 1127 "nsINetDashboardCallback", aCallback, true); 1128 1129 return rcwnData->mEventTarget->Dispatch( 1130 NewRunnableMethod<RefPtr<RcwnData>>("net::Dashboard::GetRcwnData", this, 1131 &Dashboard::GetRcwnData, rcwnData), 1132 NS_DISPATCH_NORMAL); 1133 } 1134 1135 nsresult Dashboard::GetRcwnData(RcwnData* aData) { 1136 AutoSafeJSContext cx; 1137 mozilla::dom::RcwnStatus dict; 1138 1139 dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber(); 1140 dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber(); 1141 dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber(); 1142 1143 uint32_t cacheSlow, cacheNotSlow; 1144 CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow, &cacheNotSlow); 1145 dict.mCacheSlowCount = cacheSlow; 1146 dict.mCacheNotSlowCount = cacheNotSlow; 1147 1148 dict.mPerfStats.Construct(); 1149 Sequence<mozilla::dom::RcwnPerfStats>& perfStats = dict.mPerfStats.Value(); 1150 uint32_t length = CacheFileUtils::CachePerfStats::LAST; 1151 if (!perfStats.SetCapacity(length, fallible)) { 1152 JS_ReportOutOfMemory(cx); 1153 return NS_ERROR_OUT_OF_MEMORY; 1154 } 1155 1156 for (uint32_t i = 0; i < length; i++) { 1157 CacheFileUtils::CachePerfStats::EDataType perfType = 1158 static_cast<CacheFileUtils::CachePerfStats::EDataType>(i); 1159 dom::RcwnPerfStats& elem = *perfStats.AppendElement(fallible); 1160 elem.mAvgShort = 1161 CacheFileUtils::CachePerfStats::GetAverage(perfType, false); 1162 elem.mAvgLong = CacheFileUtils::CachePerfStats::GetAverage(perfType, true); 1163 elem.mStddevLong = 1164 CacheFileUtils::CachePerfStats::GetStdDev(perfType, true); 1165 } 1166 1167 JS::Rooted<JS::Value> val(cx); 1168 if (!ToJSValue(cx, dict, &val)) { 1169 return NS_ERROR_FAILURE; 1170 } 1171 1172 aData->mCallback->OnDashboardDataAvailable(val); 1173 1174 return NS_OK; 1175 } 1176 1177 void HttpConnInfo::SetHTTPProtocolVersion(HttpVersion pv) { 1178 switch (pv) { 1179 case HttpVersion::v0_9: 1180 protocolVersion.AssignLiteral(u"http/0.9"); 1181 break; 1182 case HttpVersion::v1_0: 1183 protocolVersion.AssignLiteral(u"http/1.0"); 1184 break; 1185 case HttpVersion::v1_1: 1186 protocolVersion.AssignLiteral(u"http/1.1"); 1187 break; 1188 case HttpVersion::v2_0: 1189 protocolVersion.AssignLiteral(u"http/2"); 1190 break; 1191 case HttpVersion::v3_0: 1192 protocolVersion.AssignLiteral(u"http/3"); 1193 break; 1194 default: 1195 protocolVersion.AssignLiteral(u"unknown protocol version"); 1196 } 1197 } 1198 1199 NS_IMETHODIMP 1200 Dashboard::GetLogPath(nsACString& aLogPath) { 1201 aLogPath.SetLength(2048); 1202 uint32_t len = LogModule::GetLogFile(aLogPath.BeginWriting(), 2048); 1203 aLogPath.SetLength(len); 1204 return NS_OK; 1205 } 1206 1207 NS_IMETHODIMP 1208 Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort, 1209 const char* aProtocol, uint32_t aTimeout, 1210 nsINetDashboardCallback* aCallback) { 1211 nsresult rv; 1212 RefPtr<ConnectionData> connectionData = new ConnectionData(this); 1213 connectionData->mHost = aHost; 1214 connectionData->mPort = aPort; 1215 connectionData->mProtocol = aProtocol; 1216 connectionData->mTimeout = aTimeout; 1217 1218 connectionData->mCallback = 1219 new nsMainThreadPtrHolder<nsINetDashboardCallback>( 1220 "nsINetDashboardCallback", aCallback, true); 1221 connectionData->mEventTarget = GetCurrentSerialEventTarget(); 1222 1223 rv = TestNewConnection(connectionData); 1224 if (NS_FAILED(rv)) { 1225 mozilla::net::GetErrorString(rv, connectionData->mStatus); 1226 connectionData->mEventTarget->Dispatch( 1227 NewRunnableMethod<RefPtr<ConnectionData>>( 1228 "net::Dashboard::GetConnectionStatus", this, 1229 &Dashboard::GetConnectionStatus, connectionData), 1230 NS_DISPATCH_NORMAL); 1231 return rv; 1232 } 1233 1234 return NS_OK; 1235 } 1236 1237 nsresult Dashboard::GetConnectionStatus(ConnectionData* aConnectionData) { 1238 RefPtr<ConnectionData> connectionData = aConnectionData; 1239 AutoSafeJSContext cx; 1240 1241 mozilla::dom::ConnStatusDict dict; 1242 dict.mStatus = connectionData->mStatus; 1243 1244 JS::Rooted<JS::Value> val(cx); 1245 if (!ToJSValue(cx, dict, &val)) return NS_ERROR_FAILURE; 1246 1247 connectionData->mCallback->OnDashboardDataAvailable(val); 1248 1249 return NS_OK; 1250 } 1251 1252 nsresult Dashboard::TestNewConnection(ConnectionData* aConnectionData) { 1253 RefPtr<ConnectionData> connectionData = aConnectionData; 1254 1255 nsresult rv; 1256 if (!connectionData->mHost.Length() || 1257 !net_IsValidDNSHost(connectionData->mHost)) { 1258 return NS_ERROR_UNKNOWN_HOST; 1259 } 1260 1261 if (connectionData->mProtocol.EqualsLiteral("ssl")) { 1262 AutoTArray<nsCString, 1> socketTypes = {connectionData->mProtocol}; 1263 rv = gSocketTransportService->CreateTransport( 1264 socketTypes, connectionData->mHost, connectionData->mPort, nullptr, 1265 nullptr, getter_AddRefs(connectionData->mSocket)); 1266 } else { 1267 rv = gSocketTransportService->CreateTransport( 1268 nsTArray<nsCString>(), connectionData->mHost, connectionData->mPort, 1269 nullptr, nullptr, getter_AddRefs(connectionData->mSocket)); 1270 } 1271 if (NS_FAILED(rv)) { 1272 return rv; 1273 } 1274 1275 rv = connectionData->mSocket->SetEventSink(connectionData, 1276 GetCurrentSerialEventTarget()); 1277 if (NS_FAILED(rv)) { 1278 return rv; 1279 } 1280 1281 rv = connectionData->mSocket->OpenInputStream( 1282 nsITransport::OPEN_BLOCKING, 0, 0, 1283 getter_AddRefs(connectionData->mStreamIn)); 1284 if (NS_FAILED(rv)) { 1285 return rv; 1286 } 1287 1288 connectionData->StartTimer(connectionData->mTimeout); 1289 1290 return rv; 1291 } 1292 1293 using ErrorEntry = struct { 1294 nsresult key; 1295 const char* error; 1296 }; 1297 1298 #undef ERROR 1299 #define ERROR(key, val) {key, #key} 1300 1301 ErrorEntry socketTransportStatuses[] = { 1302 ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)), 1303 ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)), 1304 ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)), 1305 ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)), 1306 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)), 1307 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)), 1308 ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)), 1309 ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)), 1310 ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)), 1311 }; 1312 #undef ERROR 1313 1314 static void GetErrorString(nsresult rv, nsAString& errorString) { 1315 for (auto& socketTransportStatus : socketTransportStatuses) { 1316 if (socketTransportStatus.key == rv) { 1317 errorString.AssignASCII(socketTransportStatus.error); 1318 return; 1319 } 1320 } 1321 nsAutoCString errorCString; 1322 mozilla::GetErrorName(rv, errorCString); 1323 CopyUTF8toUTF16(errorCString, errorString); 1324 } 1325 1326 } // namespace net 1327 } // namespace mozilla