1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http:mozilla.org/MPL/2.0/. */
5 #include "mozilla/dom/NetDashboardBinding.h"
6 #include "mozilla/dom/ToJSValue.h"
7 #include "mozilla/ErrorNames.h"
8 #include "mozilla/net/Dashboard.h"
9 #include "mozilla/net/HttpInfo.h"
10 #include "mozilla/net/HTTPSSVC.h"
11 #include "mozilla/net/SocketProcessParent.h"
13 #include "nsICancelable.h"
14 #include "nsIDNSListener.h"
15 #include "nsIDNSService.h"
16 #include "nsIDNSRecord.h"
17 #include "nsIDNSByTypeRecord.h"
18 #include "nsIInputStream.h"
20 #include "nsINetAddr.h"
21 #include "nsISocketTransport.h"
22 #include "nsProxyRelease.h"
23 #include "nsSocketTransportService2.h"
24 #include "nsThreadUtils.h"
25 #include "nsURLHelper.h"
26 #include "mozilla/Logging.h"
27 #include "nsIOService.h"
28 #include "../cache2/CacheFileUtils.h"
30 using mozilla::AutoSafeJSContext
;
31 using mozilla::dom::Sequence
;
32 using mozilla::dom::ToJSValue
;
37 class SocketData
: public nsISupports
{
39 NS_DECL_THREADSAFE_ISUPPORTS
41 SocketData() = default;
43 uint64_t mTotalSent
{0};
44 uint64_t mTotalRecv
{0};
45 nsTArray
<SocketInfo
> mData
;
46 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
47 nsIEventTarget
* mEventTarget
{nullptr};
50 virtual ~SocketData() = default;
53 static void GetErrorString(nsresult rv
, nsAString
& errorString
);
55 NS_IMPL_ISUPPORTS0(SocketData
)
57 class HttpData
: public nsISupports
{
58 virtual ~HttpData() = default;
61 NS_DECL_THREADSAFE_ISUPPORTS
65 nsTArray
<HttpRetParams
> mData
;
66 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
67 nsIEventTarget
* mEventTarget
{nullptr};
70 NS_IMPL_ISUPPORTS0(HttpData
)
72 class WebSocketRequest
: public nsISupports
{
73 virtual ~WebSocketRequest() = default;
76 NS_DECL_THREADSAFE_ISUPPORTS
78 WebSocketRequest() = default;
80 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
81 nsIEventTarget
* mEventTarget
{nullptr};
84 NS_IMPL_ISUPPORTS0(WebSocketRequest
)
86 class DnsData
: public nsISupports
{
87 virtual ~DnsData() = default;
90 NS_DECL_THREADSAFE_ISUPPORTS
94 nsTArray
<DNSCacheEntries
> mData
;
95 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
96 nsIEventTarget
* mEventTarget
{nullptr};
99 NS_IMPL_ISUPPORTS0(DnsData
)
101 class ConnectionData
: public nsITransportEventSink
,
102 public nsITimerCallback
,
104 virtual ~ConnectionData() {
111 NS_DECL_THREADSAFE_ISUPPORTS
112 NS_DECL_NSITRANSPORTEVENTSINK
113 NS_DECL_NSITIMERCALLBACK
115 NS_IMETHOD
GetName(nsACString
& aName
) override
{
116 aName
.AssignLiteral("net::ConnectionData");
120 void StartTimer(uint32_t aTimeout
);
123 explicit ConnectionData(Dashboard
* target
) { mDashboard
= target
; }
125 nsCOMPtr
<nsISocketTransport
> mSocket
;
126 nsCOMPtr
<nsIInputStream
> mStreamIn
;
127 nsCOMPtr
<nsITimer
> mTimer
;
128 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
129 nsIEventTarget
* mEventTarget
{nullptr};
130 Dashboard
* mDashboard
;
135 uint32_t mTimeout
{0};
140 NS_IMPL_ISUPPORTS(ConnectionData
, nsITransportEventSink
, nsITimerCallback
,
143 class RcwnData
: public nsISupports
{
144 virtual ~RcwnData() = default;
147 NS_DECL_THREADSAFE_ISUPPORTS
149 RcwnData() = default;
151 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
152 nsIEventTarget
* mEventTarget
{nullptr};
155 NS_IMPL_ISUPPORTS0(RcwnData
)
158 ConnectionData::OnTransportStatus(nsITransport
* aTransport
, nsresult aStatus
,
159 int64_t aProgress
, int64_t aProgressMax
) {
160 if (aStatus
== NS_NET_STATUS_CONNECTED_TO
) {
164 GetErrorString(aStatus
, mStatus
);
165 mEventTarget
->Dispatch(NewRunnableMethod
<RefPtr
<ConnectionData
>>(
166 "net::Dashboard::GetConnectionStatus", mDashboard
,
167 &Dashboard::GetConnectionStatus
, this),
174 ConnectionData::Notify(nsITimer
* aTimer
) {
175 MOZ_ASSERT(aTimer
== mTimer
);
178 mSocket
->Close(NS_ERROR_ABORT
);
185 mStatus
.AssignLiteral(u
"NS_ERROR_NET_TIMEOUT");
186 mEventTarget
->Dispatch(NewRunnableMethod
<RefPtr
<ConnectionData
>>(
187 "net::Dashboard::GetConnectionStatus", mDashboard
,
188 &Dashboard::GetConnectionStatus
, this),
194 void ConnectionData::StartTimer(uint32_t aTimeout
) {
196 mTimer
= NS_NewTimer();
199 mTimer
->InitWithCallback(this, aTimeout
* 1000, nsITimer::TYPE_ONE_SHOT
);
202 void ConnectionData::StopTimer() {
211 class LookupArgument
: public nsISupports
{
212 virtual ~LookupArgument() = default;
215 NS_DECL_THREADSAFE_ISUPPORTS
217 LookupArgument(nsIDNSRecord
* aRecord
, LookupHelper
* aHelper
) {
222 nsCOMPtr
<nsIDNSRecord
> mRecord
;
223 RefPtr
<LookupHelper
> mHelper
;
226 NS_IMPL_ISUPPORTS0(LookupArgument
)
228 class LookupHelper final
: public nsIDNSListener
{
229 virtual ~LookupHelper() {
231 mCancel
->Cancel(NS_ERROR_ABORT
);
236 NS_DECL_THREADSAFE_ISUPPORTS
237 NS_DECL_NSIDNSLISTENER
239 LookupHelper() = default;
241 nsresult
ConstructAnswer(LookupArgument
* aArgument
);
242 nsresult
ConstructHTTPSRRAnswer(LookupArgument
* aArgument
);
245 nsCOMPtr
<nsICancelable
> mCancel
;
246 nsMainThreadPtrHandle
<nsINetDashboardCallback
> mCallback
;
247 nsIEventTarget
* mEventTarget
{nullptr};
248 nsresult mStatus
{NS_ERROR_NOT_INITIALIZED
};
251 NS_IMPL_ISUPPORTS(LookupHelper
, nsIDNSListener
)
254 LookupHelper::OnLookupComplete(nsICancelable
* aRequest
, nsIDNSRecord
* aRecord
,
256 MOZ_ASSERT(aRequest
== mCancel
);
260 nsCOMPtr
<nsIDNSHTTPSSVCRecord
> httpsRecord
= do_QueryInterface(aRecord
);
262 RefPtr
<LookupArgument
> arg
= new LookupArgument(aRecord
, this);
263 mEventTarget
->Dispatch(
264 NewRunnableMethod
<RefPtr
<LookupArgument
>>(
265 "net::LookupHelper::ConstructHTTPSRRAnswer", this,
266 &LookupHelper::ConstructHTTPSRRAnswer
, arg
),
271 RefPtr
<LookupArgument
> arg
= new LookupArgument(aRecord
, this);
272 mEventTarget
->Dispatch(NewRunnableMethod
<RefPtr
<LookupArgument
>>(
273 "net::LookupHelper::ConstructAnswer", this,
274 &LookupHelper::ConstructAnswer
, arg
),
280 nsresult
LookupHelper::ConstructAnswer(LookupArgument
* aArgument
) {
281 nsIDNSRecord
* aRecord
= aArgument
->mRecord
;
282 AutoSafeJSContext cx
;
284 mozilla::dom::DNSLookupDict dict
;
285 dict
.mAddress
.Construct();
287 Sequence
<nsString
>& addresses
= dict
.mAddress
.Value();
288 nsCOMPtr
<nsIDNSAddrRecord
> record
= do_QueryInterface(aRecord
);
289 if (NS_SUCCEEDED(mStatus
) && record
) {
292 record
->HasMore(&hasMore
);
294 nsString
* nextAddress
= addresses
.AppendElement(fallible
);
296 return NS_ERROR_OUT_OF_MEMORY
;
299 nsCString nextAddressASCII
;
300 record
->GetNextAddrAsString(nextAddressASCII
);
301 CopyASCIItoUTF16(nextAddressASCII
, *nextAddress
);
302 record
->HasMore(&hasMore
);
305 dict
.mAnswer
= false;
306 GetErrorString(mStatus
, dict
.mError
);
309 JS::Rooted
<JS::Value
> val(cx
);
310 if (!ToJSValue(cx
, dict
, &val
)) {
311 return NS_ERROR_FAILURE
;
314 this->mCallback
->OnDashboardDataAvailable(val
);
319 static void CStringToHexString(const nsACString
& aIn
, nsAString
& aOut
) {
320 static const char* const lut
= "0123456789ABCDEF";
322 size_t len
= aIn
.Length();
324 aOut
.SetCapacity(2 * len
);
325 for (size_t i
= 0; i
< aIn
.Length(); ++i
) {
326 const char c
= static_cast<char>(aIn
[i
]);
327 aOut
.Append(lut
[(c
>> 4) & 0x0F]);
328 aOut
.Append(lut
[c
& 15]);
332 nsresult
LookupHelper::ConstructHTTPSRRAnswer(LookupArgument
* aArgument
) {
333 nsCOMPtr
<nsIDNSHTTPSSVCRecord
> httpsRecord
=
334 do_QueryInterface(aArgument
->mRecord
);
336 AutoSafeJSContext cx
;
338 mozilla::dom::HTTPSRRLookupDict dict
;
339 dict
.mRecords
.Construct();
341 Sequence
<dom::HTTPSRecord
>& records
= dict
.mRecords
.Value();
342 if (NS_SUCCEEDED(mStatus
) && httpsRecord
) {
344 nsTArray
<RefPtr
<nsISVCBRecord
>> svcbRecords
;
345 httpsRecord
->GetRecords(svcbRecords
);
347 for (const auto& record
: svcbRecords
) {
348 dom::HTTPSRecord
* nextRecord
= records
.AppendElement(fallible
);
350 return NS_ERROR_OUT_OF_MEMORY
;
353 Unused
<< record
->GetPriority(&nextRecord
->mPriority
);
355 Unused
<< record
->GetName(name
);
356 CopyASCIItoUTF16(name
, nextRecord
->mTargetName
);
358 nsTArray
<RefPtr
<nsISVCParam
>> values
;
359 Unused
<< record
->GetValues(values
);
360 if (values
.IsEmpty()) {
364 for (const auto& value
: values
) {
366 Unused
<< value
->GetType(&type
);
368 case SvcParamKeyAlpn
: {
369 nextRecord
->mAlpn
.Construct();
370 nextRecord
->mAlpn
.Value().mType
= type
;
371 nsCOMPtr
<nsISVCParamAlpn
> alpnParam
= do_QueryInterface(value
);
372 nsTArray
<nsCString
> alpn
;
373 Unused
<< alpnParam
->GetAlpn(alpn
);
374 nsAutoCString alpnStr
;
375 for (const auto& str
: alpn
) {
379 CopyASCIItoUTF16(Span(alpnStr
.BeginReading(), alpnStr
.Length() - 1),
380 nextRecord
->mAlpn
.Value().mAlpn
);
383 case SvcParamKeyNoDefaultAlpn
: {
384 nextRecord
->mNoDefaultAlpn
.Construct();
385 nextRecord
->mNoDefaultAlpn
.Value().mType
= type
;
388 case SvcParamKeyPort
: {
389 nextRecord
->mPort
.Construct();
390 nextRecord
->mPort
.Value().mType
= type
;
391 nsCOMPtr
<nsISVCParamPort
> portParam
= do_QueryInterface(value
);
392 Unused
<< portParam
->GetPort(&nextRecord
->mPort
.Value().mPort
);
395 case SvcParamKeyIpv4Hint
: {
396 nextRecord
->mIpv4Hint
.Construct();
397 nextRecord
->mIpv4Hint
.Value().mType
= type
;
398 nsCOMPtr
<nsISVCParamIPv4Hint
> ipv4Param
= do_QueryInterface(value
);
399 nsTArray
<RefPtr
<nsINetAddr
>> ipv4Hint
;
400 Unused
<< ipv4Param
->GetIpv4Hint(ipv4Hint
);
401 if (!ipv4Hint
.IsEmpty()) {
402 nextRecord
->mIpv4Hint
.Value().mAddress
.Construct();
403 for (const auto& address
: ipv4Hint
) {
404 nsString
* nextAddress
= nextRecord
->mIpv4Hint
.Value()
406 .AppendElement(fallible
);
408 return NS_ERROR_OUT_OF_MEMORY
;
411 nsCString addressASCII
;
412 Unused
<< address
->GetAddress(addressASCII
);
413 CopyASCIItoUTF16(addressASCII
, *nextAddress
);
418 case SvcParamKeyIpv6Hint
: {
419 nextRecord
->mIpv6Hint
.Construct();
420 nextRecord
->mIpv6Hint
.Value().mType
= type
;
421 nsCOMPtr
<nsISVCParamIPv6Hint
> ipv6Param
= do_QueryInterface(value
);
422 nsTArray
<RefPtr
<nsINetAddr
>> ipv6Hint
;
423 Unused
<< ipv6Param
->GetIpv6Hint(ipv6Hint
);
424 if (!ipv6Hint
.IsEmpty()) {
425 nextRecord
->mIpv6Hint
.Value().mAddress
.Construct();
426 for (const auto& address
: ipv6Hint
) {
427 nsString
* nextAddress
= nextRecord
->mIpv6Hint
.Value()
429 .AppendElement(fallible
);
431 return NS_ERROR_OUT_OF_MEMORY
;
434 nsCString addressASCII
;
435 Unused
<< address
->GetAddress(addressASCII
);
436 CopyASCIItoUTF16(addressASCII
, *nextAddress
);
441 case SvcParamKeyEchConfig
: {
442 nextRecord
->mEchConfig
.Construct();
443 nextRecord
->mEchConfig
.Value().mType
= type
;
444 nsCOMPtr
<nsISVCParamEchConfig
> echConfigParam
=
445 do_QueryInterface(value
);
446 nsCString echConfigStr
;
447 Unused
<< echConfigParam
->GetEchconfig(echConfigStr
);
448 CStringToHexString(echConfigStr
,
449 nextRecord
->mEchConfig
.Value().mEchConfig
);
452 case SvcParamKeyODoHConfig
: {
453 nextRecord
->mODoHConfig
.Construct();
454 nextRecord
->mODoHConfig
.Value().mType
= type
;
455 nsCOMPtr
<nsISVCParamODoHConfig
> ODoHConfigParam
=
456 do_QueryInterface(value
);
457 nsCString ODoHConfigStr
;
458 Unused
<< ODoHConfigParam
->GetODoHConfig(ODoHConfigStr
);
459 CStringToHexString(ODoHConfigStr
,
460 nextRecord
->mODoHConfig
.Value().mODoHConfig
);
469 dict
.mAnswer
= false;
470 GetErrorString(mStatus
, dict
.mError
);
473 JS::Rooted
<JS::Value
> val(cx
);
474 if (!ToJSValue(cx
, dict
, &val
)) {
475 return NS_ERROR_FAILURE
;
478 this->mCallback
->OnDashboardDataAvailable(val
);
483 NS_IMPL_ISUPPORTS(Dashboard
, nsIDashboard
, nsIDashboardEventNotifier
)
485 Dashboard::Dashboard() { mEnableLogging
= false; }
488 Dashboard::RequestSockets(nsINetDashboardCallback
* aCallback
) {
489 RefPtr
<SocketData
> socketData
= new SocketData();
490 socketData
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
491 "nsINetDashboardCallback", aCallback
, true);
492 socketData
->mEventTarget
= GetCurrentSerialEventTarget();
494 if (nsIOService::UseSocketProcess()) {
495 if (!gIOService
->SocketProcessReady()) {
496 return NS_ERROR_NOT_AVAILABLE
;
499 RefPtr
<Dashboard
> self(this);
500 SocketProcessParent::GetSingleton()->SendGetSocketData()->Then(
501 GetMainThreadSerialEventTarget(), __func__
,
502 [self
{std::move(self
)},
503 socketData
{std::move(socketData
)}](SocketDataArgs
&& args
) {
504 socketData
->mData
.Assign(args
.info());
505 socketData
->mTotalSent
= args
.totalSent();
506 socketData
->mTotalRecv
= args
.totalRecv();
507 socketData
->mEventTarget
->Dispatch(
508 NewRunnableMethod
<RefPtr
<SocketData
>>(
509 "net::Dashboard::GetSockets", self
, &Dashboard::GetSockets
,
513 [self
](const mozilla::ipc::ResponseRejectReason
) {});
517 gSocketTransportService
->Dispatch(
518 NewRunnableMethod
<RefPtr
<SocketData
>>(
519 "net::Dashboard::GetSocketsDispatch", this,
520 &Dashboard::GetSocketsDispatch
, socketData
),
525 nsresult
Dashboard::GetSocketsDispatch(SocketData
* aSocketData
) {
526 RefPtr
<SocketData
> socketData
= aSocketData
;
527 if (gSocketTransportService
) {
528 gSocketTransportService
->GetSocketConnections(&socketData
->mData
);
529 socketData
->mTotalSent
= gSocketTransportService
->GetSentBytes();
530 socketData
->mTotalRecv
= gSocketTransportService
->GetReceivedBytes();
532 socketData
->mEventTarget
->Dispatch(
533 NewRunnableMethod
<RefPtr
<SocketData
>>("net::Dashboard::GetSockets", this,
534 &Dashboard::GetSockets
, socketData
),
539 nsresult
Dashboard::GetSockets(SocketData
* aSocketData
) {
540 RefPtr
<SocketData
> socketData
= aSocketData
;
541 AutoSafeJSContext cx
;
543 mozilla::dom::SocketsDict dict
;
544 dict
.mSockets
.Construct();
548 Sequence
<mozilla::dom::SocketElement
>& sockets
= dict
.mSockets
.Value();
550 uint32_t length
= socketData
->mData
.Length();
551 if (!sockets
.SetCapacity(length
, fallible
)) {
552 JS_ReportOutOfMemory(cx
);
553 return NS_ERROR_OUT_OF_MEMORY
;
556 for (uint32_t i
= 0; i
< socketData
->mData
.Length(); i
++) {
557 dom::SocketElement
& mSocket
= *sockets
.AppendElement(fallible
);
558 CopyASCIItoUTF16(socketData
->mData
[i
].host
, mSocket
.mHost
);
559 mSocket
.mPort
= socketData
->mData
[i
].port
;
560 mSocket
.mActive
= socketData
->mData
[i
].active
;
561 CopyASCIItoUTF16(socketData
->mData
[i
].type
, mSocket
.mType
);
562 mSocket
.mSent
= (double)socketData
->mData
[i
].sent
;
563 mSocket
.mReceived
= (double)socketData
->mData
[i
].received
;
564 dict
.mSent
+= socketData
->mData
[i
].sent
;
565 dict
.mReceived
+= socketData
->mData
[i
].received
;
568 dict
.mSent
+= socketData
->mTotalSent
;
569 dict
.mReceived
+= socketData
->mTotalRecv
;
570 JS::Rooted
<JS::Value
> val(cx
);
571 if (!ToJSValue(cx
, dict
, &val
)) return NS_ERROR_FAILURE
;
572 socketData
->mCallback
->OnDashboardDataAvailable(val
);
578 Dashboard::RequestHttpConnections(nsINetDashboardCallback
* aCallback
) {
579 RefPtr
<HttpData
> httpData
= new HttpData();
580 httpData
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
581 "nsINetDashboardCallback", aCallback
, true);
582 httpData
->mEventTarget
= GetCurrentSerialEventTarget();
584 if (nsIOService::UseSocketProcess()) {
585 if (!gIOService
->SocketProcessReady()) {
586 return NS_ERROR_NOT_AVAILABLE
;
589 RefPtr
<Dashboard
> self(this);
590 SocketProcessParent::GetSingleton()->SendGetHttpConnectionData()->Then(
591 GetMainThreadSerialEventTarget(), __func__
,
592 [self
{std::move(self
)}, httpData
](nsTArray
<HttpRetParams
>&& params
) {
593 httpData
->mData
.Assign(std::move(params
));
594 self
->GetHttpConnections(httpData
);
595 httpData
->mEventTarget
->Dispatch(
596 NewRunnableMethod
<RefPtr
<HttpData
>>(
597 "net::Dashboard::GetHttpConnections", self
,
598 &Dashboard::GetHttpConnections
, httpData
),
601 [self
](const mozilla::ipc::ResponseRejectReason
) {});
605 gSocketTransportService
->Dispatch(NewRunnableMethod
<RefPtr
<HttpData
>>(
606 "net::Dashboard::GetHttpDispatch", this,
607 &Dashboard::GetHttpDispatch
, httpData
),
612 nsresult
Dashboard::GetHttpDispatch(HttpData
* aHttpData
) {
613 RefPtr
<HttpData
> httpData
= aHttpData
;
614 HttpInfo::GetHttpConnectionData(&httpData
->mData
);
615 httpData
->mEventTarget
->Dispatch(
616 NewRunnableMethod
<RefPtr
<HttpData
>>("net::Dashboard::GetHttpConnections",
617 this, &Dashboard::GetHttpConnections
,
623 nsresult
Dashboard::GetHttpConnections(HttpData
* aHttpData
) {
624 RefPtr
<HttpData
> httpData
= aHttpData
;
625 AutoSafeJSContext cx
;
627 mozilla::dom::HttpConnDict dict
;
628 dict
.mConnections
.Construct();
630 using mozilla::dom::DnsAndSockInfoDict
;
631 using mozilla::dom::HttpConnectionElement
;
632 using mozilla::dom::HttpConnInfo
;
633 Sequence
<HttpConnectionElement
>& connections
= dict
.mConnections
.Value();
635 uint32_t length
= httpData
->mData
.Length();
636 if (!connections
.SetCapacity(length
, fallible
)) {
637 JS_ReportOutOfMemory(cx
);
638 return NS_ERROR_OUT_OF_MEMORY
;
641 for (uint32_t i
= 0; i
< httpData
->mData
.Length(); i
++) {
642 HttpConnectionElement
& connection
= *connections
.AppendElement(fallible
);
644 CopyASCIItoUTF16(httpData
->mData
[i
].host
, connection
.mHost
);
645 connection
.mPort
= httpData
->mData
[i
].port
;
646 CopyASCIItoUTF16(httpData
->mData
[i
].httpVersion
, connection
.mHttpVersion
);
647 connection
.mSsl
= httpData
->mData
[i
].ssl
;
649 connection
.mActive
.Construct();
650 connection
.mIdle
.Construct();
651 connection
.mDnsAndSocks
.Construct();
653 Sequence
<HttpConnInfo
>& active
= connection
.mActive
.Value();
654 Sequence
<HttpConnInfo
>& idle
= connection
.mIdle
.Value();
655 Sequence
<DnsAndSockInfoDict
>& dnsAndSocks
= connection
.mDnsAndSocks
.Value();
657 if (!active
.SetCapacity(httpData
->mData
[i
].active
.Length(), fallible
) ||
658 !idle
.SetCapacity(httpData
->mData
[i
].idle
.Length(), fallible
) ||
659 !dnsAndSocks
.SetCapacity(httpData
->mData
[i
].dnsAndSocks
.Length(),
661 JS_ReportOutOfMemory(cx
);
662 return NS_ERROR_OUT_OF_MEMORY
;
665 for (uint32_t j
= 0; j
< httpData
->mData
[i
].active
.Length(); j
++) {
666 HttpConnInfo
& info
= *active
.AppendElement(fallible
);
667 info
.mRtt
= httpData
->mData
[i
].active
[j
].rtt
;
668 info
.mTtl
= httpData
->mData
[i
].active
[j
].ttl
;
669 info
.mProtocolVersion
= httpData
->mData
[i
].active
[j
].protocolVersion
;
672 for (uint32_t j
= 0; j
< httpData
->mData
[i
].idle
.Length(); j
++) {
673 HttpConnInfo
& info
= *idle
.AppendElement(fallible
);
674 info
.mRtt
= httpData
->mData
[i
].idle
[j
].rtt
;
675 info
.mTtl
= httpData
->mData
[i
].idle
[j
].ttl
;
676 info
.mProtocolVersion
= httpData
->mData
[i
].idle
[j
].protocolVersion
;
679 for (uint32_t j
= 0; j
< httpData
->mData
[i
].dnsAndSocks
.Length(); j
++) {
680 DnsAndSockInfoDict
& info
= *dnsAndSocks
.AppendElement(fallible
);
681 info
.mSpeculative
= httpData
->mData
[i
].dnsAndSocks
[j
].speculative
;
685 JS::Rooted
<JS::Value
> val(cx
);
686 if (!ToJSValue(cx
, dict
, &val
)) {
687 return NS_ERROR_FAILURE
;
690 httpData
->mCallback
->OnDashboardDataAvailable(val
);
696 Dashboard::GetEnableLogging(bool* value
) {
697 *value
= mEnableLogging
;
702 Dashboard::SetEnableLogging(const bool value
) {
703 mEnableLogging
= value
;
708 Dashboard::AddHost(const nsACString
& aHost
, uint32_t aSerial
, bool aEncrypted
) {
709 if (mEnableLogging
) {
710 mozilla::MutexAutoLock
lock(mWs
.lock
);
711 LogData
mData(nsCString(aHost
), aSerial
, aEncrypted
);
712 if (mWs
.data
.Contains(mData
)) {
715 // XXX(Bug 1631371) Check if this should use a fallible operation as it
716 // pretended earlier.
717 mWs
.data
.AppendElement(mData
);
720 return NS_ERROR_FAILURE
;
724 Dashboard::RemoveHost(const nsACString
& aHost
, uint32_t aSerial
) {
725 if (mEnableLogging
) {
726 mozilla::MutexAutoLock
lock(mWs
.lock
);
727 int32_t index
= mWs
.IndexOf(nsCString(aHost
), aSerial
);
728 if (index
== -1) return NS_ERROR_FAILURE
;
729 mWs
.data
.RemoveElementAt(index
);
732 return NS_ERROR_FAILURE
;
736 Dashboard::NewMsgSent(const nsACString
& aHost
, uint32_t aSerial
,
738 if (mEnableLogging
) {
739 mozilla::MutexAutoLock
lock(mWs
.lock
);
740 int32_t index
= mWs
.IndexOf(nsCString(aHost
), aSerial
);
741 if (index
== -1) return NS_ERROR_FAILURE
;
742 mWs
.data
[index
].mMsgSent
++;
743 mWs
.data
[index
].mSizeSent
+= aLength
;
746 return NS_ERROR_FAILURE
;
750 Dashboard::NewMsgReceived(const nsACString
& aHost
, uint32_t aSerial
,
752 if (mEnableLogging
) {
753 mozilla::MutexAutoLock
lock(mWs
.lock
);
754 int32_t index
= mWs
.IndexOf(nsCString(aHost
), aSerial
);
755 if (index
== -1) return NS_ERROR_FAILURE
;
756 mWs
.data
[index
].mMsgReceived
++;
757 mWs
.data
[index
].mSizeReceived
+= aLength
;
760 return NS_ERROR_FAILURE
;
764 Dashboard::RequestWebsocketConnections(nsINetDashboardCallback
* aCallback
) {
765 RefPtr
<WebSocketRequest
> wsRequest
= new WebSocketRequest();
766 wsRequest
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
767 "nsINetDashboardCallback", aCallback
, true);
768 wsRequest
->mEventTarget
= GetCurrentSerialEventTarget();
770 wsRequest
->mEventTarget
->Dispatch(
771 NewRunnableMethod
<RefPtr
<WebSocketRequest
>>(
772 "net::Dashboard::GetWebSocketConnections", this,
773 &Dashboard::GetWebSocketConnections
, wsRequest
),
778 nsresult
Dashboard::GetWebSocketConnections(WebSocketRequest
* aWsRequest
) {
779 RefPtr
<WebSocketRequest
> wsRequest
= aWsRequest
;
780 AutoSafeJSContext cx
;
782 mozilla::dom::WebSocketDict dict
;
783 dict
.mWebsockets
.Construct();
784 Sequence
<mozilla::dom::WebSocketElement
>& websockets
=
785 dict
.mWebsockets
.Value();
787 mozilla::MutexAutoLock
lock(mWs
.lock
);
788 uint32_t length
= mWs
.data
.Length();
789 if (!websockets
.SetCapacity(length
, fallible
)) {
790 JS_ReportOutOfMemory(cx
);
791 return NS_ERROR_OUT_OF_MEMORY
;
794 for (uint32_t i
= 0; i
< mWs
.data
.Length(); i
++) {
795 dom::WebSocketElement
& websocket
= *websockets
.AppendElement(fallible
);
796 CopyASCIItoUTF16(mWs
.data
[i
].mHost
, websocket
.mHostport
);
797 websocket
.mMsgsent
= mWs
.data
[i
].mMsgSent
;
798 websocket
.mMsgreceived
= mWs
.data
[i
].mMsgReceived
;
799 websocket
.mSentsize
= mWs
.data
[i
].mSizeSent
;
800 websocket
.mReceivedsize
= mWs
.data
[i
].mSizeReceived
;
801 websocket
.mEncrypted
= mWs
.data
[i
].mEncrypted
;
804 JS::Rooted
<JS::Value
> val(cx
);
805 if (!ToJSValue(cx
, dict
, &val
)) {
806 return NS_ERROR_FAILURE
;
808 wsRequest
->mCallback
->OnDashboardDataAvailable(val
);
814 Dashboard::RequestDNSInfo(nsINetDashboardCallback
* aCallback
) {
815 RefPtr
<DnsData
> dnsData
= new DnsData();
816 dnsData
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
817 "nsINetDashboardCallback", aCallback
, true);
820 dnsData
->mData
.Clear();
821 dnsData
->mEventTarget
= GetCurrentSerialEventTarget();
824 mDnsService
= do_GetService("@mozilla.org/network/dns-service;1", &rv
);
830 if (nsIOService::UseSocketProcess()) {
831 if (!gIOService
->SocketProcessReady()) {
832 return NS_ERROR_NOT_AVAILABLE
;
835 RefPtr
<Dashboard
> self(this);
836 SocketProcessParent::GetSingleton()->SendGetDNSCacheEntries()->Then(
837 GetMainThreadSerialEventTarget(), __func__
,
838 [self
{std::move(self
)},
839 dnsData
{std::move(dnsData
)}](nsTArray
<DNSCacheEntries
>&& entries
) {
840 dnsData
->mData
.Assign(std::move(entries
));
841 dnsData
->mEventTarget
->Dispatch(
842 NewRunnableMethod
<RefPtr
<DnsData
>>(
843 "net::Dashboard::GetDNSCacheEntries", self
,
844 &Dashboard::GetDNSCacheEntries
, dnsData
),
847 [self
](const mozilla::ipc::ResponseRejectReason
) {});
851 gSocketTransportService
->Dispatch(
852 NewRunnableMethod
<RefPtr
<DnsData
>>("net::Dashboard::GetDnsInfoDispatch",
853 this, &Dashboard::GetDnsInfoDispatch
,
859 nsresult
Dashboard::GetDnsInfoDispatch(DnsData
* aDnsData
) {
860 RefPtr
<DnsData
> dnsData
= aDnsData
;
862 mDnsService
->GetDNSCacheEntries(&dnsData
->mData
);
864 dnsData
->mEventTarget
->Dispatch(
865 NewRunnableMethod
<RefPtr
<DnsData
>>("net::Dashboard::GetDNSCacheEntries",
866 this, &Dashboard::GetDNSCacheEntries
,
872 nsresult
Dashboard::GetDNSCacheEntries(DnsData
* dnsData
) {
873 AutoSafeJSContext cx
;
875 mozilla::dom::DNSCacheDict dict
;
876 dict
.mEntries
.Construct();
877 Sequence
<mozilla::dom::DnsCacheEntry
>& entries
= dict
.mEntries
.Value();
879 uint32_t length
= dnsData
->mData
.Length();
880 if (!entries
.SetCapacity(length
, fallible
)) {
881 JS_ReportOutOfMemory(cx
);
882 return NS_ERROR_OUT_OF_MEMORY
;
885 for (uint32_t i
= 0; i
< dnsData
->mData
.Length(); i
++) {
886 dom::DnsCacheEntry
& entry
= *entries
.AppendElement(fallible
);
887 entry
.mHostaddr
.Construct();
889 Sequence
<nsString
>& addrs
= entry
.mHostaddr
.Value();
890 if (!addrs
.SetCapacity(dnsData
->mData
[i
].hostaddr
.Length(), fallible
)) {
891 JS_ReportOutOfMemory(cx
);
892 return NS_ERROR_OUT_OF_MEMORY
;
895 CopyASCIItoUTF16(dnsData
->mData
[i
].hostname
, entry
.mHostname
);
896 entry
.mExpiration
= dnsData
->mData
[i
].expiration
;
897 entry
.mTrr
= dnsData
->mData
[i
].TRR
;
899 for (uint32_t j
= 0; j
< dnsData
->mData
[i
].hostaddr
.Length(); j
++) {
900 nsString
* addr
= addrs
.AppendElement(fallible
);
902 JS_ReportOutOfMemory(cx
);
903 return NS_ERROR_OUT_OF_MEMORY
;
905 CopyASCIItoUTF16(dnsData
->mData
[i
].hostaddr
[j
], *addr
);
908 if (dnsData
->mData
[i
].family
== PR_AF_INET6
) {
909 entry
.mFamily
.AssignLiteral(u
"ipv6");
911 entry
.mFamily
.AssignLiteral(u
"ipv4");
914 entry
.mOriginAttributesSuffix
=
915 NS_ConvertUTF8toUTF16(dnsData
->mData
[i
].originAttributesSuffix
);
916 entry
.mFlags
= NS_ConvertUTF8toUTF16(dnsData
->mData
[i
].flags
);
919 JS::Rooted
<JS::Value
> val(cx
);
920 if (!ToJSValue(cx
, dict
, &val
)) {
921 return NS_ERROR_FAILURE
;
923 dnsData
->mCallback
->OnDashboardDataAvailable(val
);
929 Dashboard::RequestDNSLookup(const nsACString
& aHost
,
930 nsINetDashboardCallback
* aCallback
) {
934 mDnsService
= do_GetService("@mozilla.org/network/dns-service;1", &rv
);
940 RefPtr
<LookupHelper
> helper
= new LookupHelper();
941 helper
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
942 "nsINetDashboardCallback", aCallback
, true);
943 helper
->mEventTarget
= GetCurrentSerialEventTarget();
944 OriginAttributes attrs
;
945 rv
= mDnsService
->AsyncResolveNative(
946 aHost
, nsIDNSService::RESOLVE_TYPE_DEFAULT
,
947 nsIDNSService::RESOLVE_DEFAULT_FLAGS
, nullptr, helper
.get(),
948 NS_GetCurrentThread(), attrs
, getter_AddRefs(helper
->mCancel
));
953 Dashboard::RequestDNSHTTPSRRLookup(const nsACString
& aHost
,
954 nsINetDashboardCallback
* aCallback
) {
958 mDnsService
= do_GetService("@mozilla.org/network/dns-service;1", &rv
);
964 RefPtr
<LookupHelper
> helper
= new LookupHelper();
965 helper
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
966 "nsINetDashboardCallback", aCallback
, true);
967 helper
->mEventTarget
= GetCurrentSerialEventTarget();
968 OriginAttributes attrs
;
969 rv
= mDnsService
->AsyncResolveNative(
970 aHost
, nsIDNSService::RESOLVE_TYPE_HTTPSSVC
,
971 nsIDNSService::RESOLVE_DEFAULT_FLAGS
, nullptr, helper
.get(),
972 NS_GetCurrentThread(), attrs
, getter_AddRefs(helper
->mCancel
));
977 Dashboard::RequestRcwnStats(nsINetDashboardCallback
* aCallback
) {
978 RefPtr
<RcwnData
> rcwnData
= new RcwnData();
979 rcwnData
->mEventTarget
= GetCurrentSerialEventTarget();
980 rcwnData
->mCallback
= new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
981 "nsINetDashboardCallback", aCallback
, true);
983 return rcwnData
->mEventTarget
->Dispatch(
984 NewRunnableMethod
<RefPtr
<RcwnData
>>("net::Dashboard::GetRcwnData", this,
985 &Dashboard::GetRcwnData
, rcwnData
),
989 nsresult
Dashboard::GetRcwnData(RcwnData
* aData
) {
990 AutoSafeJSContext cx
;
991 mozilla::dom::RcwnStatus dict
;
993 dict
.mTotalNetworkRequests
= gIOService
->GetTotalRequestNumber();
994 dict
.mRcwnCacheWonCount
= gIOService
->GetCacheWonRequestNumber();
995 dict
.mRcwnNetWonCount
= gIOService
->GetNetWonRequestNumber();
997 uint32_t cacheSlow
, cacheNotSlow
;
998 CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow
, &cacheNotSlow
);
999 dict
.mCacheSlowCount
= cacheSlow
;
1000 dict
.mCacheNotSlowCount
= cacheNotSlow
;
1002 dict
.mPerfStats
.Construct();
1003 Sequence
<mozilla::dom::RcwnPerfStats
>& perfStats
= dict
.mPerfStats
.Value();
1004 uint32_t length
= CacheFileUtils::CachePerfStats::LAST
;
1005 if (!perfStats
.SetCapacity(length
, fallible
)) {
1006 JS_ReportOutOfMemory(cx
);
1007 return NS_ERROR_OUT_OF_MEMORY
;
1010 for (uint32_t i
= 0; i
< length
; i
++) {
1011 CacheFileUtils::CachePerfStats::EDataType perfType
=
1012 static_cast<CacheFileUtils::CachePerfStats::EDataType
>(i
);
1013 dom::RcwnPerfStats
& elem
= *perfStats
.AppendElement(fallible
);
1015 CacheFileUtils::CachePerfStats::GetAverage(perfType
, false);
1016 elem
.mAvgLong
= CacheFileUtils::CachePerfStats::GetAverage(perfType
, true);
1018 CacheFileUtils::CachePerfStats::GetStdDev(perfType
, true);
1021 JS::Rooted
<JS::Value
> val(cx
);
1022 if (!ToJSValue(cx
, dict
, &val
)) {
1023 return NS_ERROR_FAILURE
;
1026 aData
->mCallback
->OnDashboardDataAvailable(val
);
1031 void HttpConnInfo::SetHTTPProtocolVersion(HttpVersion pv
) {
1033 case HttpVersion::v0_9
:
1034 protocolVersion
.AssignLiteral(u
"http/0.9");
1036 case HttpVersion::v1_0
:
1037 protocolVersion
.AssignLiteral(u
"http/1.0");
1039 case HttpVersion::v1_1
:
1040 protocolVersion
.AssignLiteral(u
"http/1.1");
1042 case HttpVersion::v2_0
:
1043 protocolVersion
.AssignLiteral(u
"http/2");
1045 case HttpVersion::v3_0
:
1046 protocolVersion
.AssignLiteral(u
"http/3");
1049 protocolVersion
.AssignLiteral(u
"unknown protocol version");
1054 Dashboard::GetLogPath(nsACString
& aLogPath
) {
1055 aLogPath
.SetLength(2048);
1056 uint32_t len
= LogModule::GetLogFile(aLogPath
.BeginWriting(), 2048);
1057 aLogPath
.SetLength(len
);
1062 Dashboard::RequestConnection(const nsACString
& aHost
, uint32_t aPort
,
1063 const char* aProtocol
, uint32_t aTimeout
,
1064 nsINetDashboardCallback
* aCallback
) {
1066 RefPtr
<ConnectionData
> connectionData
= new ConnectionData(this);
1067 connectionData
->mHost
= aHost
;
1068 connectionData
->mPort
= aPort
;
1069 connectionData
->mProtocol
= aProtocol
;
1070 connectionData
->mTimeout
= aTimeout
;
1072 connectionData
->mCallback
=
1073 new nsMainThreadPtrHolder
<nsINetDashboardCallback
>(
1074 "nsINetDashboardCallback", aCallback
, true);
1075 connectionData
->mEventTarget
= GetCurrentSerialEventTarget();
1077 rv
= TestNewConnection(connectionData
);
1078 if (NS_FAILED(rv
)) {
1079 mozilla::net::GetErrorString(rv
, connectionData
->mStatus
);
1080 connectionData
->mEventTarget
->Dispatch(
1081 NewRunnableMethod
<RefPtr
<ConnectionData
>>(
1082 "net::Dashboard::GetConnectionStatus", this,
1083 &Dashboard::GetConnectionStatus
, connectionData
),
1084 NS_DISPATCH_NORMAL
);
1091 nsresult
Dashboard::GetConnectionStatus(ConnectionData
* aConnectionData
) {
1092 RefPtr
<ConnectionData
> connectionData
= aConnectionData
;
1093 AutoSafeJSContext cx
;
1095 mozilla::dom::ConnStatusDict dict
;
1096 dict
.mStatus
= connectionData
->mStatus
;
1098 JS::Rooted
<JS::Value
> val(cx
);
1099 if (!ToJSValue(cx
, dict
, &val
)) return NS_ERROR_FAILURE
;
1101 connectionData
->mCallback
->OnDashboardDataAvailable(val
);
1106 nsresult
Dashboard::TestNewConnection(ConnectionData
* aConnectionData
) {
1107 RefPtr
<ConnectionData
> connectionData
= aConnectionData
;
1110 if (!connectionData
->mHost
.Length() ||
1111 !net_IsValidHostName(connectionData
->mHost
)) {
1112 return NS_ERROR_UNKNOWN_HOST
;
1115 if (connectionData
->mProtocol
.EqualsLiteral("ssl")) {
1116 AutoTArray
<nsCString
, 1> socketTypes
= {connectionData
->mProtocol
};
1117 rv
= gSocketTransportService
->CreateTransport(
1118 socketTypes
, connectionData
->mHost
, connectionData
->mPort
, nullptr,
1119 nullptr, getter_AddRefs(connectionData
->mSocket
));
1121 rv
= gSocketTransportService
->CreateTransport(
1122 nsTArray
<nsCString
>(), connectionData
->mHost
, connectionData
->mPort
,
1123 nullptr, nullptr, getter_AddRefs(connectionData
->mSocket
));
1125 if (NS_FAILED(rv
)) {
1129 rv
= connectionData
->mSocket
->SetEventSink(connectionData
,
1130 GetCurrentSerialEventTarget());
1131 if (NS_FAILED(rv
)) {
1135 rv
= connectionData
->mSocket
->OpenInputStream(
1136 nsITransport::OPEN_BLOCKING
, 0, 0,
1137 getter_AddRefs(connectionData
->mStreamIn
));
1138 if (NS_FAILED(rv
)) {
1142 connectionData
->StartTimer(connectionData
->mTimeout
);
1147 using ErrorEntry
= struct {
1153 #define ERROR(key, val) \
1156 ErrorEntry socketTransportStatuses
[] = {
1157 ERROR(NS_NET_STATUS_RESOLVING_HOST
, FAILURE(3)),
1158 ERROR(NS_NET_STATUS_RESOLVED_HOST
, FAILURE(11)),
1159 ERROR(NS_NET_STATUS_CONNECTING_TO
, FAILURE(7)),
1160 ERROR(NS_NET_STATUS_CONNECTED_TO
, FAILURE(4)),
1161 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING
, FAILURE(12)),
1162 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED
, FAILURE(13)),
1163 ERROR(NS_NET_STATUS_SENDING_TO
, FAILURE(5)),
1164 ERROR(NS_NET_STATUS_WAITING_FOR
, FAILURE(10)),
1165 ERROR(NS_NET_STATUS_RECEIVING_FROM
, FAILURE(6)),
1169 static void GetErrorString(nsresult rv
, nsAString
& errorString
) {
1170 for (auto& socketTransportStatus
: socketTransportStatuses
) {
1171 if (socketTransportStatus
.key
== rv
) {
1172 errorString
.AssignASCII(socketTransportStatus
.error
);
1176 nsAutoCString errorCString
;
1177 mozilla::GetErrorName(rv
, errorCString
);
1178 CopyUTF8toUTF16(errorCString
, errorString
);
1182 } // namespace mozilla