tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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