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/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"
12 #include "nsHttp.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"
19 #include "nsINamed.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"
29
30 using mozilla::AutoSafeJSContext;
31 using mozilla::dom::Sequence;
32 using mozilla::dom::ToJSValue;
33
34 namespace mozilla {
35 namespace net {
36
37 class SocketData : public nsISupports {
38 public:
39 NS_DECL_THREADSAFE_ISUPPORTS
40
41 SocketData() = default;
42
43 uint64_t mTotalSent{0};
44 uint64_t mTotalRecv{0};
45 nsTArray<SocketInfo> mData;
46 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
47 nsIEventTarget* mEventTarget{nullptr};
48
49 private:
50 virtual ~SocketData() = default;
51 };
52
53 static void GetErrorString(nsresult rv, nsAString& errorString);
54
55 NS_IMPL_ISUPPORTS0(SocketData)
56
57 class HttpData : public nsISupports {
58 virtual ~HttpData() = default;
59
60 public:
61 NS_DECL_THREADSAFE_ISUPPORTS
62
63 HttpData() = default;
64
65 nsTArray<HttpRetParams> mData;
66 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
67 nsIEventTarget* mEventTarget{nullptr};
68 };
69
70 NS_IMPL_ISUPPORTS0(HttpData)
71
72 class WebSocketRequest : public nsISupports {
73 virtual ~WebSocketRequest() = default;
74
75 public:
76 NS_DECL_THREADSAFE_ISUPPORTS
77
78 WebSocketRequest() = default;
79
80 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
81 nsIEventTarget* mEventTarget{nullptr};
82 };
83
84 NS_IMPL_ISUPPORTS0(WebSocketRequest)
85
86 class DnsData : public nsISupports {
87 virtual ~DnsData() = default;
88
89 public:
90 NS_DECL_THREADSAFE_ISUPPORTS
91
92 DnsData() = default;
93
94 nsTArray<DNSCacheEntries> mData;
95 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
96 nsIEventTarget* mEventTarget{nullptr};
97 };
98
99 NS_IMPL_ISUPPORTS0(DnsData)
100
101 class ConnectionData : public nsITransportEventSink,
102 public nsITimerCallback,
103 public nsINamed {
~ConnectionData()104 virtual ~ConnectionData() {
105 if (mTimer) {
106 mTimer->Cancel();
107 }
108 }
109
110 public:
111 NS_DECL_THREADSAFE_ISUPPORTS
112 NS_DECL_NSITRANSPORTEVENTSINK
113 NS_DECL_NSITIMERCALLBACK
114
GetName(nsACString & aName)115 NS_IMETHOD GetName(nsACString& aName) override {
116 aName.AssignLiteral("net::ConnectionData");
117 return NS_OK;
118 }
119
120 void StartTimer(uint32_t aTimeout);
121 void StopTimer();
122
ConnectionData(Dashboard * target)123 explicit ConnectionData(Dashboard* target) { mDashboard = target; }
124
125 nsCOMPtr<nsISocketTransport> mSocket;
126 nsCOMPtr<nsIInputStream> mStreamIn;
127 nsCOMPtr<nsITimer> mTimer;
128 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
129 nsIEventTarget* mEventTarget{nullptr};
130 Dashboard* mDashboard;
131
132 nsCString mHost;
133 uint32_t mPort{0};
134 nsCString mProtocol;
135 uint32_t mTimeout{0};
136
137 nsString mStatus;
138 };
139
140 NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback,
141 nsINamed)
142
143 class RcwnData : public nsISupports {
144 virtual ~RcwnData() = default;
145
146 public:
147 NS_DECL_THREADSAFE_ISUPPORTS
148
149 RcwnData() = default;
150
151 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
152 nsIEventTarget* mEventTarget{nullptr};
153 };
154
NS_IMPL_ISUPPORTS0(RcwnData)155 NS_IMPL_ISUPPORTS0(RcwnData)
156
157 NS_IMETHODIMP
158 ConnectionData::OnTransportStatus(nsITransport* aTransport, nsresult aStatus,
159 int64_t aProgress, int64_t aProgressMax) {
160 if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
161 StopTimer();
162 }
163
164 GetErrorString(aStatus, mStatus);
165 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>(
166 "net::Dashboard::GetConnectionStatus", mDashboard,
167 &Dashboard::GetConnectionStatus, this),
168 NS_DISPATCH_NORMAL);
169
170 return NS_OK;
171 }
172
173 NS_IMETHODIMP
Notify(nsITimer * aTimer)174 ConnectionData::Notify(nsITimer* aTimer) {
175 MOZ_ASSERT(aTimer == mTimer);
176
177 if (mSocket) {
178 mSocket->Close(NS_ERROR_ABORT);
179 mSocket = nullptr;
180 mStreamIn = nullptr;
181 }
182
183 mTimer = nullptr;
184
185 mStatus.AssignLiteral(u"NS_ERROR_NET_TIMEOUT");
186 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>(
187 "net::Dashboard::GetConnectionStatus", mDashboard,
188 &Dashboard::GetConnectionStatus, this),
189 NS_DISPATCH_NORMAL);
190
191 return NS_OK;
192 }
193
StartTimer(uint32_t aTimeout)194 void ConnectionData::StartTimer(uint32_t aTimeout) {
195 if (!mTimer) {
196 mTimer = NS_NewTimer();
197 }
198
199 mTimer->InitWithCallback(this, aTimeout * 1000, nsITimer::TYPE_ONE_SHOT);
200 }
201
StopTimer()202 void ConnectionData::StopTimer() {
203 if (mTimer) {
204 mTimer->Cancel();
205 mTimer = nullptr;
206 }
207 }
208
209 class LookupHelper;
210
211 class LookupArgument : public nsISupports {
212 virtual ~LookupArgument() = default;
213
214 public:
215 NS_DECL_THREADSAFE_ISUPPORTS
216
LookupArgument(nsIDNSRecord * aRecord,LookupHelper * aHelper)217 LookupArgument(nsIDNSRecord* aRecord, LookupHelper* aHelper) {
218 mRecord = aRecord;
219 mHelper = aHelper;
220 }
221
222 nsCOMPtr<nsIDNSRecord> mRecord;
223 RefPtr<LookupHelper> mHelper;
224 };
225
226 NS_IMPL_ISUPPORTS0(LookupArgument)
227
228 class LookupHelper final : public nsIDNSListener {
~LookupHelper()229 virtual ~LookupHelper() {
230 if (mCancel) {
231 mCancel->Cancel(NS_ERROR_ABORT);
232 }
233 }
234
235 public:
236 NS_DECL_THREADSAFE_ISUPPORTS
237 NS_DECL_NSIDNSLISTENER
238
239 LookupHelper() = default;
240
241 nsresult ConstructAnswer(LookupArgument* aArgument);
242 nsresult ConstructHTTPSRRAnswer(LookupArgument* aArgument);
243
244 public:
245 nsCOMPtr<nsICancelable> mCancel;
246 nsMainThreadPtrHandle<nsINetDashboardCallback> mCallback;
247 nsIEventTarget* mEventTarget{nullptr};
248 nsresult mStatus{NS_ERROR_NOT_INITIALIZED};
249 };
250
NS_IMPL_ISUPPORTS(LookupHelper,nsIDNSListener)251 NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener)
252
253 NS_IMETHODIMP
254 LookupHelper::OnLookupComplete(nsICancelable* aRequest, nsIDNSRecord* aRecord,
255 nsresult aStatus) {
256 MOZ_ASSERT(aRequest == mCancel);
257 mCancel = nullptr;
258 mStatus = aStatus;
259
260 nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord = do_QueryInterface(aRecord);
261 if (httpsRecord) {
262 RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
263 mEventTarget->Dispatch(
264 NewRunnableMethod<RefPtr<LookupArgument>>(
265 "net::LookupHelper::ConstructHTTPSRRAnswer", this,
266 &LookupHelper::ConstructHTTPSRRAnswer, arg),
267 NS_DISPATCH_NORMAL);
268 return NS_OK;
269 }
270
271 RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
272 mEventTarget->Dispatch(NewRunnableMethod<RefPtr<LookupArgument>>(
273 "net::LookupHelper::ConstructAnswer", this,
274 &LookupHelper::ConstructAnswer, arg),
275 NS_DISPATCH_NORMAL);
276
277 return NS_OK;
278 }
279
ConstructAnswer(LookupArgument * aArgument)280 nsresult LookupHelper::ConstructAnswer(LookupArgument* aArgument) {
281 nsIDNSRecord* aRecord = aArgument->mRecord;
282 AutoSafeJSContext cx;
283
284 mozilla::dom::DNSLookupDict dict;
285 dict.mAddress.Construct();
286
287 Sequence<nsString>& addresses = dict.mAddress.Value();
288 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(aRecord);
289 if (NS_SUCCEEDED(mStatus) && record) {
290 dict.mAnswer = true;
291 bool hasMore;
292 record->HasMore(&hasMore);
293 while (hasMore) {
294 nsString* nextAddress = addresses.AppendElement(fallible);
295 if (!nextAddress) {
296 return NS_ERROR_OUT_OF_MEMORY;
297 }
298
299 nsCString nextAddressASCII;
300 record->GetNextAddrAsString(nextAddressASCII);
301 CopyASCIItoUTF16(nextAddressASCII, *nextAddress);
302 record->HasMore(&hasMore);
303 }
304 } else {
305 dict.mAnswer = false;
306 GetErrorString(mStatus, dict.mError);
307 }
308
309 JS::RootedValue val(cx);
310 if (!ToJSValue(cx, dict, &val)) {
311 return NS_ERROR_FAILURE;
312 }
313
314 this->mCallback->OnDashboardDataAvailable(val);
315
316 return NS_OK;
317 }
318
CStringToHexString(const nsACString & aIn,nsAString & aOut)319 static void CStringToHexString(const nsACString& aIn, nsAString& aOut) {
320 static const char* const lut = "0123456789ABCDEF";
321
322 size_t len = aIn.Length();
323
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]);
329 }
330 }
331
ConstructHTTPSRRAnswer(LookupArgument * aArgument)332 nsresult LookupHelper::ConstructHTTPSRRAnswer(LookupArgument* aArgument) {
333 nsCOMPtr<nsIDNSHTTPSSVCRecord> httpsRecord =
334 do_QueryInterface(aArgument->mRecord);
335
336 AutoSafeJSContext cx;
337
338 mozilla::dom::HTTPSRRLookupDict dict;
339 dict.mRecords.Construct();
340
341 Sequence<dom::HTTPSRecord>& records = dict.mRecords.Value();
342 if (NS_SUCCEEDED(mStatus) && httpsRecord) {
343 dict.mAnswer = true;
344 nsTArray<RefPtr<nsISVCBRecord>> svcbRecords;
345 httpsRecord->GetRecords(svcbRecords);
346
347 for (const auto& record : svcbRecords) {
348 dom::HTTPSRecord* nextRecord = records.AppendElement(fallible);
349 if (!nextRecord) {
350 return NS_ERROR_OUT_OF_MEMORY;
351 }
352
353 Unused << record->GetPriority(&nextRecord->mPriority);
354 nsCString name;
355 Unused << record->GetName(name);
356 CopyASCIItoUTF16(name, nextRecord->mTargetName);
357
358 nsTArray<RefPtr<nsISVCParam>> values;
359 Unused << record->GetValues(values);
360 if (values.IsEmpty()) {
361 continue;
362 }
363
364 for (const auto& value : values) {
365 uint16_t type;
366 Unused << value->GetType(&type);
367 switch (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) {
376 alpnStr.Append(str);
377 alpnStr.Append(',');
378 }
379 CopyASCIItoUTF16(Span(alpnStr.BeginReading(), alpnStr.Length() - 1),
380 nextRecord->mAlpn.Value().mAlpn);
381 break;
382 }
383 case SvcParamKeyNoDefaultAlpn: {
384 nextRecord->mNoDefaultAlpn.Construct();
385 nextRecord->mNoDefaultAlpn.Value().mType = type;
386 break;
387 }
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);
393 break;
394 }
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()
405 .mAddress.Value()
406 .AppendElement(fallible);
407 if (!nextAddress) {
408 return NS_ERROR_OUT_OF_MEMORY;
409 }
410
411 nsCString addressASCII;
412 Unused << address->GetAddress(addressASCII);
413 CopyASCIItoUTF16(addressASCII, *nextAddress);
414 }
415 }
416 break;
417 }
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()
428 .mAddress.Value()
429 .AppendElement(fallible);
430 if (!nextAddress) {
431 return NS_ERROR_OUT_OF_MEMORY;
432 }
433
434 nsCString addressASCII;
435 Unused << address->GetAddress(addressASCII);
436 CopyASCIItoUTF16(addressASCII, *nextAddress);
437 }
438 }
439 break;
440 }
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);
450 break;
451 }
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);
461 break;
462 }
463 default:
464 break;
465 }
466 }
467 }
468 } else {
469 dict.mAnswer = false;
470 GetErrorString(mStatus, dict.mError);
471 }
472
473 JS::RootedValue val(cx);
474 if (!ToJSValue(cx, dict, &val)) {
475 return NS_ERROR_FAILURE;
476 }
477
478 this->mCallback->OnDashboardDataAvailable(val);
479
480 return NS_OK;
481 }
482
NS_IMPL_ISUPPORTS(Dashboard,nsIDashboard,nsIDashboardEventNotifier)483 NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
484
485 Dashboard::Dashboard() { mEnableLogging = false; }
486
487 NS_IMETHODIMP
RequestSockets(nsINetDashboardCallback * aCallback)488 Dashboard::RequestSockets(nsINetDashboardCallback* aCallback) {
489 RefPtr<SocketData> socketData = new SocketData();
490 socketData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
491 "nsINetDashboardCallback", aCallback, true);
492 socketData->mEventTarget = GetCurrentEventTarget();
493
494 if (nsIOService::UseSocketProcess()) {
495 if (!gIOService->SocketProcessReady()) {
496 return NS_ERROR_NOT_AVAILABLE;
497 }
498
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,
510 socketData),
511 NS_DISPATCH_NORMAL);
512 },
513 [self](const mozilla::ipc::ResponseRejectReason) {});
514 return NS_OK;
515 }
516
517 gSocketTransportService->Dispatch(
518 NewRunnableMethod<RefPtr<SocketData>>(
519 "net::Dashboard::GetSocketsDispatch", this,
520 &Dashboard::GetSocketsDispatch, socketData),
521 NS_DISPATCH_NORMAL);
522 return NS_OK;
523 }
524
GetSocketsDispatch(SocketData * aSocketData)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();
531 }
532 socketData->mEventTarget->Dispatch(
533 NewRunnableMethod<RefPtr<SocketData>>("net::Dashboard::GetSockets", this,
534 &Dashboard::GetSockets, socketData),
535 NS_DISPATCH_NORMAL);
536 return NS_OK;
537 }
538
GetSockets(SocketData * aSocketData)539 nsresult Dashboard::GetSockets(SocketData* aSocketData) {
540 RefPtr<SocketData> socketData = aSocketData;
541 AutoSafeJSContext cx;
542
543 mozilla::dom::SocketsDict dict;
544 dict.mSockets.Construct();
545 dict.mSent = 0;
546 dict.mReceived = 0;
547
548 Sequence<mozilla::dom::SocketElement>& sockets = dict.mSockets.Value();
549
550 uint32_t length = socketData->mData.Length();
551 if (!sockets.SetCapacity(length, fallible)) {
552 JS_ReportOutOfMemory(cx);
553 return NS_ERROR_OUT_OF_MEMORY;
554 }
555
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 mSocket.mTcp = socketData->mData[i].tcp;
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;
566 }
567
568 dict.mSent += socketData->mTotalSent;
569 dict.mReceived += socketData->mTotalRecv;
570 JS::RootedValue val(cx);
571 if (!ToJSValue(cx, dict, &val)) return NS_ERROR_FAILURE;
572 socketData->mCallback->OnDashboardDataAvailable(val);
573
574 return NS_OK;
575 }
576
577 NS_IMETHODIMP
RequestHttpConnections(nsINetDashboardCallback * aCallback)578 Dashboard::RequestHttpConnections(nsINetDashboardCallback* aCallback) {
579 RefPtr<HttpData> httpData = new HttpData();
580 httpData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
581 "nsINetDashboardCallback", aCallback, true);
582 httpData->mEventTarget = GetCurrentEventTarget();
583
584 if (nsIOService::UseSocketProcess()) {
585 if (!gIOService->SocketProcessReady()) {
586 return NS_ERROR_NOT_AVAILABLE;
587 }
588
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),
599 NS_DISPATCH_NORMAL);
600 },
601 [self](const mozilla::ipc::ResponseRejectReason) {});
602 return NS_OK;
603 }
604
605 gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<HttpData>>(
606 "net::Dashboard::GetHttpDispatch", this,
607 &Dashboard::GetHttpDispatch, httpData),
608 NS_DISPATCH_NORMAL);
609 return NS_OK;
610 }
611
GetHttpDispatch(HttpData * aHttpData)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,
618 httpData),
619 NS_DISPATCH_NORMAL);
620 return NS_OK;
621 }
622
GetHttpConnections(HttpData * aHttpData)623 nsresult Dashboard::GetHttpConnections(HttpData* aHttpData) {
624 RefPtr<HttpData> httpData = aHttpData;
625 AutoSafeJSContext cx;
626
627 mozilla::dom::HttpConnDict dict;
628 dict.mConnections.Construct();
629
630 using mozilla::dom::DnsAndSockInfoDict;
631 using mozilla::dom::HttpConnectionElement;
632 using mozilla::dom::HttpConnInfo;
633 Sequence<HttpConnectionElement>& connections = dict.mConnections.Value();
634
635 uint32_t length = httpData->mData.Length();
636 if (!connections.SetCapacity(length, fallible)) {
637 JS_ReportOutOfMemory(cx);
638 return NS_ERROR_OUT_OF_MEMORY;
639 }
640
641 for (uint32_t i = 0; i < httpData->mData.Length(); i++) {
642 HttpConnectionElement& connection = *connections.AppendElement(fallible);
643
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;
648
649 connection.mActive.Construct();
650 connection.mIdle.Construct();
651 connection.mDnsAndSocks.Construct();
652
653 Sequence<HttpConnInfo>& active = connection.mActive.Value();
654 Sequence<HttpConnInfo>& idle = connection.mIdle.Value();
655 Sequence<DnsAndSockInfoDict>& dnsAndSocks = connection.mDnsAndSocks.Value();
656
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(),
660 fallible)) {
661 JS_ReportOutOfMemory(cx);
662 return NS_ERROR_OUT_OF_MEMORY;
663 }
664
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;
670 }
671
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;
677 }
678
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;
682 }
683 }
684
685 JS::RootedValue val(cx);
686 if (!ToJSValue(cx, dict, &val)) {
687 return NS_ERROR_FAILURE;
688 }
689
690 httpData->mCallback->OnDashboardDataAvailable(val);
691
692 return NS_OK;
693 }
694
695 NS_IMETHODIMP
GetEnableLogging(bool * value)696 Dashboard::GetEnableLogging(bool* value) {
697 *value = mEnableLogging;
698 return NS_OK;
699 }
700
701 NS_IMETHODIMP
SetEnableLogging(const bool value)702 Dashboard::SetEnableLogging(const bool value) {
703 mEnableLogging = value;
704 return NS_OK;
705 }
706
707 NS_IMETHODIMP
AddHost(const nsACString & aHost,uint32_t aSerial,bool aEncrypted)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)) {
713 return NS_OK;
714 }
715 // XXX(Bug 1631371) Check if this should use a fallible operation as it
716 // pretended earlier.
717 mWs.data.AppendElement(mData);
718 return NS_OK;
719 }
720 return NS_ERROR_FAILURE;
721 }
722
723 NS_IMETHODIMP
RemoveHost(const nsACString & aHost,uint32_t aSerial)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);
730 return NS_OK;
731 }
732 return NS_ERROR_FAILURE;
733 }
734
735 NS_IMETHODIMP
NewMsgSent(const nsACString & aHost,uint32_t aSerial,uint32_t aLength)736 Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial,
737 uint32_t aLength) {
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;
744 return NS_OK;
745 }
746 return NS_ERROR_FAILURE;
747 }
748
749 NS_IMETHODIMP
NewMsgReceived(const nsACString & aHost,uint32_t aSerial,uint32_t aLength)750 Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial,
751 uint32_t aLength) {
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;
758 return NS_OK;
759 }
760 return NS_ERROR_FAILURE;
761 }
762
763 NS_IMETHODIMP
RequestWebsocketConnections(nsINetDashboardCallback * aCallback)764 Dashboard::RequestWebsocketConnections(nsINetDashboardCallback* aCallback) {
765 RefPtr<WebSocketRequest> wsRequest = new WebSocketRequest();
766 wsRequest->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
767 "nsINetDashboardCallback", aCallback, true);
768 wsRequest->mEventTarget = GetCurrentEventTarget();
769
770 wsRequest->mEventTarget->Dispatch(
771 NewRunnableMethod<RefPtr<WebSocketRequest>>(
772 "net::Dashboard::GetWebSocketConnections", this,
773 &Dashboard::GetWebSocketConnections, wsRequest),
774 NS_DISPATCH_NORMAL);
775 return NS_OK;
776 }
777
GetWebSocketConnections(WebSocketRequest * aWsRequest)778 nsresult Dashboard::GetWebSocketConnections(WebSocketRequest* aWsRequest) {
779 RefPtr<WebSocketRequest> wsRequest = aWsRequest;
780 AutoSafeJSContext cx;
781
782 mozilla::dom::WebSocketDict dict;
783 dict.mWebsockets.Construct();
784 Sequence<mozilla::dom::WebSocketElement>& websockets =
785 dict.mWebsockets.Value();
786
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;
792 }
793
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;
802 }
803
804 JS::RootedValue val(cx);
805 if (!ToJSValue(cx, dict, &val)) {
806 return NS_ERROR_FAILURE;
807 }
808 wsRequest->mCallback->OnDashboardDataAvailable(val);
809
810 return NS_OK;
811 }
812
813 NS_IMETHODIMP
RequestDNSInfo(nsINetDashboardCallback * aCallback)814 Dashboard::RequestDNSInfo(nsINetDashboardCallback* aCallback) {
815 RefPtr<DnsData> dnsData = new DnsData();
816 dnsData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
817 "nsINetDashboardCallback", aCallback, true);
818
819 nsresult rv;
820 dnsData->mData.Clear();
821 dnsData->mEventTarget = GetCurrentEventTarget();
822
823 if (!mDnsService) {
824 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
825 if (NS_FAILED(rv)) {
826 return rv;
827 }
828 }
829
830 if (nsIOService::UseSocketProcess()) {
831 if (!gIOService->SocketProcessReady()) {
832 return NS_ERROR_NOT_AVAILABLE;
833 }
834
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),
845 NS_DISPATCH_NORMAL);
846 },
847 [self](const mozilla::ipc::ResponseRejectReason) {});
848 return NS_OK;
849 }
850
851 gSocketTransportService->Dispatch(
852 NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDnsInfoDispatch",
853 this, &Dashboard::GetDnsInfoDispatch,
854 dnsData),
855 NS_DISPATCH_NORMAL);
856 return NS_OK;
857 }
858
GetDnsInfoDispatch(DnsData * aDnsData)859 nsresult Dashboard::GetDnsInfoDispatch(DnsData* aDnsData) {
860 RefPtr<DnsData> dnsData = aDnsData;
861 if (mDnsService) {
862 mDnsService->GetDNSCacheEntries(&dnsData->mData);
863 }
864 dnsData->mEventTarget->Dispatch(
865 NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDNSCacheEntries",
866 this, &Dashboard::GetDNSCacheEntries,
867 dnsData),
868 NS_DISPATCH_NORMAL);
869 return NS_OK;
870 }
871
GetDNSCacheEntries(DnsData * dnsData)872 nsresult Dashboard::GetDNSCacheEntries(DnsData* dnsData) {
873 AutoSafeJSContext cx;
874
875 mozilla::dom::DNSCacheDict dict;
876 dict.mEntries.Construct();
877 Sequence<mozilla::dom::DnsCacheEntry>& entries = dict.mEntries.Value();
878
879 uint32_t length = dnsData->mData.Length();
880 if (!entries.SetCapacity(length, fallible)) {
881 JS_ReportOutOfMemory(cx);
882 return NS_ERROR_OUT_OF_MEMORY;
883 }
884
885 for (uint32_t i = 0; i < dnsData->mData.Length(); i++) {
886 dom::DnsCacheEntry& entry = *entries.AppendElement(fallible);
887 entry.mHostaddr.Construct();
888
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;
893 }
894
895 CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname);
896 entry.mExpiration = dnsData->mData[i].expiration;
897 entry.mTrr = dnsData->mData[i].TRR;
898
899 for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) {
900 nsString* addr = addrs.AppendElement(fallible);
901 if (!addr) {
902 JS_ReportOutOfMemory(cx);
903 return NS_ERROR_OUT_OF_MEMORY;
904 }
905 CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], *addr);
906 }
907
908 if (dnsData->mData[i].family == PR_AF_INET6) {
909 entry.mFamily.AssignLiteral(u"ipv6");
910 } else {
911 entry.mFamily.AssignLiteral(u"ipv4");
912 }
913
914 entry.mOriginAttributesSuffix =
915 NS_ConvertUTF8toUTF16(dnsData->mData[i].originAttributesSuffix);
916 }
917
918 JS::RootedValue val(cx);
919 if (!ToJSValue(cx, dict, &val)) {
920 return NS_ERROR_FAILURE;
921 }
922 dnsData->mCallback->OnDashboardDataAvailable(val);
923
924 return NS_OK;
925 }
926
927 NS_IMETHODIMP
RequestDNSLookup(const nsACString & aHost,nsINetDashboardCallback * aCallback)928 Dashboard::RequestDNSLookup(const nsACString& aHost,
929 nsINetDashboardCallback* aCallback) {
930 nsresult rv;
931
932 if (!mDnsService) {
933 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
934 if (NS_FAILED(rv)) {
935 return rv;
936 }
937 }
938
939 RefPtr<LookupHelper> helper = new LookupHelper();
940 helper->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
941 "nsINetDashboardCallback", aCallback, true);
942 helper->mEventTarget = GetCurrentEventTarget();
943 OriginAttributes attrs;
944 rv = mDnsService->AsyncResolveNative(
945 aHost, nsIDNSService::RESOLVE_TYPE_DEFAULT, 0, nullptr, helper.get(),
946 NS_GetCurrentThread(), attrs, getter_AddRefs(helper->mCancel));
947 return rv;
948 }
949
950 NS_IMETHODIMP
RequestDNSHTTPSRRLookup(const nsACString & aHost,nsINetDashboardCallback * aCallback)951 Dashboard::RequestDNSHTTPSRRLookup(const nsACString& aHost,
952 nsINetDashboardCallback* aCallback) {
953 nsresult rv;
954
955 if (!mDnsService) {
956 mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
957 if (NS_FAILED(rv)) {
958 return rv;
959 }
960 }
961
962 RefPtr<LookupHelper> helper = new LookupHelper();
963 helper->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
964 "nsINetDashboardCallback", aCallback, true);
965 helper->mEventTarget = GetCurrentEventTarget();
966 OriginAttributes attrs;
967 rv = mDnsService->AsyncResolveNative(
968 aHost, nsIDNSService::RESOLVE_TYPE_HTTPSSVC, 0, nullptr, helper.get(),
969 NS_GetCurrentThread(), attrs, getter_AddRefs(helper->mCancel));
970 return rv;
971 }
972
973 NS_IMETHODIMP
RequestRcwnStats(nsINetDashboardCallback * aCallback)974 Dashboard::RequestRcwnStats(nsINetDashboardCallback* aCallback) {
975 RefPtr<RcwnData> rcwnData = new RcwnData();
976 rcwnData->mEventTarget = GetCurrentEventTarget();
977 rcwnData->mCallback = new nsMainThreadPtrHolder<nsINetDashboardCallback>(
978 "nsINetDashboardCallback", aCallback, true);
979
980 return rcwnData->mEventTarget->Dispatch(
981 NewRunnableMethod<RefPtr<RcwnData>>("net::Dashboard::GetRcwnData", this,
982 &Dashboard::GetRcwnData, rcwnData),
983 NS_DISPATCH_NORMAL);
984 }
985
GetRcwnData(RcwnData * aData)986 nsresult Dashboard::GetRcwnData(RcwnData* aData) {
987 AutoSafeJSContext cx;
988 mozilla::dom::RcwnStatus dict;
989
990 dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber();
991 dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
992 dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
993
994 uint32_t cacheSlow, cacheNotSlow;
995 CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow, &cacheNotSlow);
996 dict.mCacheSlowCount = cacheSlow;
997 dict.mCacheNotSlowCount = cacheNotSlow;
998
999 dict.mPerfStats.Construct();
1000 Sequence<mozilla::dom::RcwnPerfStats>& perfStats = dict.mPerfStats.Value();
1001 uint32_t length = CacheFileUtils::CachePerfStats::LAST;
1002 if (!perfStats.SetCapacity(length, fallible)) {
1003 JS_ReportOutOfMemory(cx);
1004 return NS_ERROR_OUT_OF_MEMORY;
1005 }
1006
1007 for (uint32_t i = 0; i < length; i++) {
1008 CacheFileUtils::CachePerfStats::EDataType perfType =
1009 static_cast<CacheFileUtils::CachePerfStats::EDataType>(i);
1010 dom::RcwnPerfStats& elem = *perfStats.AppendElement(fallible);
1011 elem.mAvgShort =
1012 CacheFileUtils::CachePerfStats::GetAverage(perfType, false);
1013 elem.mAvgLong = CacheFileUtils::CachePerfStats::GetAverage(perfType, true);
1014 elem.mStddevLong =
1015 CacheFileUtils::CachePerfStats::GetStdDev(perfType, true);
1016 }
1017
1018 JS::RootedValue val(cx);
1019 if (!ToJSValue(cx, dict, &val)) {
1020 return NS_ERROR_FAILURE;
1021 }
1022
1023 aData->mCallback->OnDashboardDataAvailable(val);
1024
1025 return NS_OK;
1026 }
1027
SetHTTPProtocolVersion(HttpVersion pv)1028 void HttpConnInfo::SetHTTPProtocolVersion(HttpVersion pv) {
1029 switch (pv) {
1030 case HttpVersion::v0_9:
1031 protocolVersion.AssignLiteral(u"http/0.9");
1032 break;
1033 case HttpVersion::v1_0:
1034 protocolVersion.AssignLiteral(u"http/1.0");
1035 break;
1036 case HttpVersion::v1_1:
1037 protocolVersion.AssignLiteral(u"http/1.1");
1038 break;
1039 case HttpVersion::v2_0:
1040 protocolVersion.AssignLiteral(u"http/2");
1041 break;
1042 case HttpVersion::v3_0:
1043 protocolVersion.AssignLiteral(u"http/3");
1044 break;
1045 default:
1046 protocolVersion.AssignLiteral(u"unknown protocol version");
1047 }
1048 }
1049
1050 NS_IMETHODIMP
GetLogPath(nsACString & aLogPath)1051 Dashboard::GetLogPath(nsACString& aLogPath) {
1052 aLogPath.SetLength(2048);
1053 uint32_t len = LogModule::GetLogFile(aLogPath.BeginWriting(), 2048);
1054 aLogPath.SetLength(len);
1055 return NS_OK;
1056 }
1057
1058 NS_IMETHODIMP
RequestConnection(const nsACString & aHost,uint32_t aPort,const char * aProtocol,uint32_t aTimeout,nsINetDashboardCallback * aCallback)1059 Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
1060 const char* aProtocol, uint32_t aTimeout,
1061 nsINetDashboardCallback* aCallback) {
1062 nsresult rv;
1063 RefPtr<ConnectionData> connectionData = new ConnectionData(this);
1064 connectionData->mHost = aHost;
1065 connectionData->mPort = aPort;
1066 connectionData->mProtocol = aProtocol;
1067 connectionData->mTimeout = aTimeout;
1068
1069 connectionData->mCallback =
1070 new nsMainThreadPtrHolder<nsINetDashboardCallback>(
1071 "nsINetDashboardCallback", aCallback, true);
1072 connectionData->mEventTarget = GetCurrentEventTarget();
1073
1074 rv = TestNewConnection(connectionData);
1075 if (NS_FAILED(rv)) {
1076 mozilla::net::GetErrorString(rv, connectionData->mStatus);
1077 connectionData->mEventTarget->Dispatch(
1078 NewRunnableMethod<RefPtr<ConnectionData>>(
1079 "net::Dashboard::GetConnectionStatus", this,
1080 &Dashboard::GetConnectionStatus, connectionData),
1081 NS_DISPATCH_NORMAL);
1082 return rv;
1083 }
1084
1085 return NS_OK;
1086 }
1087
GetConnectionStatus(ConnectionData * aConnectionData)1088 nsresult Dashboard::GetConnectionStatus(ConnectionData* aConnectionData) {
1089 RefPtr<ConnectionData> connectionData = aConnectionData;
1090 AutoSafeJSContext cx;
1091
1092 mozilla::dom::ConnStatusDict dict;
1093 dict.mStatus = connectionData->mStatus;
1094
1095 JS::RootedValue val(cx);
1096 if (!ToJSValue(cx, dict, &val)) return NS_ERROR_FAILURE;
1097
1098 connectionData->mCallback->OnDashboardDataAvailable(val);
1099
1100 return NS_OK;
1101 }
1102
TestNewConnection(ConnectionData * aConnectionData)1103 nsresult Dashboard::TestNewConnection(ConnectionData* aConnectionData) {
1104 RefPtr<ConnectionData> connectionData = aConnectionData;
1105
1106 nsresult rv;
1107 if (!connectionData->mHost.Length() ||
1108 !net_IsValidHostName(connectionData->mHost)) {
1109 return NS_ERROR_UNKNOWN_HOST;
1110 }
1111
1112 if (connectionData->mProtocol.EqualsLiteral("ssl")) {
1113 AutoTArray<nsCString, 1> socketTypes = {connectionData->mProtocol};
1114 rv = gSocketTransportService->CreateTransport(
1115 socketTypes, connectionData->mHost, connectionData->mPort, nullptr,
1116 nullptr, getter_AddRefs(connectionData->mSocket));
1117 } else {
1118 rv = gSocketTransportService->CreateTransport(
1119 nsTArray<nsCString>(), connectionData->mHost, connectionData->mPort,
1120 nullptr, nullptr, getter_AddRefs(connectionData->mSocket));
1121 }
1122 if (NS_FAILED(rv)) {
1123 return rv;
1124 }
1125
1126 rv = connectionData->mSocket->SetEventSink(connectionData,
1127 GetCurrentEventTarget());
1128 if (NS_FAILED(rv)) {
1129 return rv;
1130 }
1131
1132 rv = connectionData->mSocket->OpenInputStream(
1133 nsITransport::OPEN_BLOCKING, 0, 0,
1134 getter_AddRefs(connectionData->mStreamIn));
1135 if (NS_FAILED(rv)) {
1136 return rv;
1137 }
1138
1139 connectionData->StartTimer(connectionData->mTimeout);
1140
1141 return rv;
1142 }
1143
1144 using ErrorEntry = struct {
1145 nsresult key;
1146 const char* error;
1147 };
1148
1149 #undef ERROR
1150 #define ERROR(key, val) \
1151 { key, #key }
1152
1153 ErrorEntry socketTransportStatuses[] = {
1154 ERROR(NS_NET_STATUS_RESOLVING_HOST, FAILURE(3)),
1155 ERROR(NS_NET_STATUS_RESOLVED_HOST, FAILURE(11)),
1156 ERROR(NS_NET_STATUS_CONNECTING_TO, FAILURE(7)),
1157 ERROR(NS_NET_STATUS_CONNECTED_TO, FAILURE(4)),
1158 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)),
1159 ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED, FAILURE(13)),
1160 ERROR(NS_NET_STATUS_SENDING_TO, FAILURE(5)),
1161 ERROR(NS_NET_STATUS_WAITING_FOR, FAILURE(10)),
1162 ERROR(NS_NET_STATUS_RECEIVING_FROM, FAILURE(6)),
1163 };
1164 #undef ERROR
1165
GetErrorString(nsresult rv,nsAString & errorString)1166 static void GetErrorString(nsresult rv, nsAString& errorString) {
1167 for (auto& socketTransportStatus : socketTransportStatuses) {
1168 if (socketTransportStatus.key == rv) {
1169 errorString.AssignASCII(socketTransportStatus.error);
1170 return;
1171 }
1172 }
1173 nsAutoCString errorCString;
1174 mozilla::GetErrorName(rv, errorCString);
1175 CopyUTF8toUTF16(errorCString, errorString);
1176 }
1177
1178 } // namespace net
1179 } // namespace mozilla
1180