Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/Dashboard.cpp
Line
Count
Source (jump to first uncovered line)
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 "nsHttp.h"
11
#include "nsICancelable.h"
12
#include "nsIDNSService.h"
13
#include "nsIDNSRecord.h"
14
#include "nsIInputStream.h"
15
#include "nsINamed.h"
16
#include "nsISocketTransport.h"
17
#include "nsIThread.h"
18
#include "nsProxyRelease.h"
19
#include "nsSocketTransportService2.h"
20
#include "nsThreadUtils.h"
21
#include "nsURLHelper.h"
22
#include "mozilla/Logging.h"
23
#include "nsIOService.h"
24
#include "../cache2/CacheFileUtils.h"
25
26
using mozilla::AutoSafeJSContext;
27
using mozilla::dom::Sequence;
28
using mozilla::dom::ToJSValue;
29
30
namespace mozilla {
31
namespace net {
32
33
class SocketData
34
    : public nsISupports
35
{
36
public:
37
    NS_DECL_THREADSAFE_ISUPPORTS
38
39
    SocketData()
40
0
    {
41
0
        mTotalSent = 0;
42
0
        mTotalRecv = 0;
43
0
        mEventTarget = nullptr;
44
0
    }
45
46
    uint64_t mTotalSent;
47
    uint64_t mTotalRecv;
48
    nsTArray<SocketInfo> mData;
49
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
50
    nsIEventTarget *mEventTarget;
51
52
private:
53
0
    virtual ~SocketData() = default;
54
};
55
56
static void GetErrorString(nsresult rv, nsAString& errorString);
57
58
NS_IMPL_ISUPPORTS0(SocketData)
59
60
61
class HttpData
62
    : public nsISupports
63
{
64
0
    virtual ~HttpData() = default;
65
66
public:
67
    NS_DECL_THREADSAFE_ISUPPORTS
68
69
    HttpData()
70
0
    {
71
0
        mEventTarget = nullptr;
72
0
    }
73
74
    nsTArray<HttpRetParams> mData;
75
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
76
    nsIEventTarget *mEventTarget;
77
};
78
79
NS_IMPL_ISUPPORTS0(HttpData)
80
81
82
class WebSocketRequest
83
    : public nsISupports
84
{
85
0
    virtual ~WebSocketRequest() = default;
86
87
public:
88
    NS_DECL_THREADSAFE_ISUPPORTS
89
90
    WebSocketRequest()
91
0
    {
92
0
        mEventTarget = nullptr;
93
0
    }
94
95
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
96
    nsIEventTarget *mEventTarget;
97
};
98
99
NS_IMPL_ISUPPORTS0(WebSocketRequest)
100
101
102
class DnsData
103
    : public nsISupports
104
{
105
0
    virtual ~DnsData() = default;
106
107
public:
108
    NS_DECL_THREADSAFE_ISUPPORTS
109
110
    DnsData()
111
0
    {
112
0
        mEventTarget = nullptr;
113
0
    }
114
115
    nsTArray<DNSCacheEntries> mData;
116
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
117
    nsIEventTarget *mEventTarget;
118
};
119
120
NS_IMPL_ISUPPORTS0(DnsData)
121
122
123
class ConnectionData
124
    : public nsITransportEventSink
125
    , public nsITimerCallback
126
    , public nsINamed
127
{
128
    virtual ~ConnectionData()
129
0
    {
130
0
        if (mTimer) {
131
0
            mTimer->Cancel();
132
0
        }
133
0
    }
134
135
public:
136
    NS_DECL_THREADSAFE_ISUPPORTS
137
    NS_DECL_NSITRANSPORTEVENTSINK
138
    NS_DECL_NSITIMERCALLBACK
139
140
    NS_IMETHOD GetName(nsACString& aName) override
141
0
    {
142
0
      aName.AssignLiteral("net::ConnectionData");
143
0
      return NS_OK;
144
0
    }
145
146
147
    void StartTimer(uint32_t aTimeout);
148
    void StopTimer();
149
150
    explicit ConnectionData(Dashboard* target)
151
        : mPort(0)
152
        , mProtocol(nullptr)
153
        , mTimeout(0)
154
0
    {
155
0
        mEventTarget = nullptr;
156
0
        mDashboard = target;
157
0
    }
158
159
    nsCOMPtr<nsISocketTransport> mSocket;
160
    nsCOMPtr<nsIInputStream> mStreamIn;
161
    nsCOMPtr<nsITimer> mTimer;
162
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
163
    nsIEventTarget *mEventTarget;
164
    Dashboard *mDashboard;
165
166
    nsCString mHost;
167
    uint32_t mPort;
168
    const char *mProtocol;
169
    uint32_t mTimeout;
170
171
    nsString mStatus;
172
};
173
174
NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback, nsINamed)
175
176
177
class RcwnData
178
    : public nsISupports
179
{
180
0
    virtual ~RcwnData() = default;
181
182
public:
183
    NS_DECL_THREADSAFE_ISUPPORTS
184
185
    RcwnData()
186
0
    {
187
0
        mEventTarget = nullptr;
188
0
    }
189
190
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
191
    nsIEventTarget *mEventTarget;
192
};
193
194
NS_IMPL_ISUPPORTS0(RcwnData)
195
196
NS_IMETHODIMP
197
ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
198
                                  int64_t aProgress, int64_t aProgressMax)
199
0
{
200
0
    if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
201
0
        StopTimer();
202
0
    }
203
0
204
0
    GetErrorString(aStatus, mStatus);
205
0
    mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
206
0
                           ("net::Dashboard::GetConnectionStatus",
207
0
                            mDashboard, &Dashboard::GetConnectionStatus, this),
208
0
                           NS_DISPATCH_NORMAL);
209
0
210
0
    return NS_OK;
211
0
}
212
213
NS_IMETHODIMP
214
ConnectionData::Notify(nsITimer *aTimer)
215
0
{
216
0
    MOZ_ASSERT(aTimer == mTimer);
217
0
218
0
    if (mSocket) {
219
0
        mSocket->Close(NS_ERROR_ABORT);
220
0
        mSocket = nullptr;
221
0
        mStreamIn = nullptr;
222
0
    }
223
0
224
0
    mTimer = nullptr;
225
0
226
0
    mStatus.AssignLiteral(u"NS_ERROR_NET_TIMEOUT");
227
0
    mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
228
0
                           ("net::Dashboard::GetConnectionStatus",
229
0
                            mDashboard, &Dashboard::GetConnectionStatus, this),
230
0
                           NS_DISPATCH_NORMAL);
231
0
232
0
    return NS_OK;
233
0
}
234
235
void
236
ConnectionData::StartTimer(uint32_t aTimeout)
237
0
{
238
0
    if (!mTimer) {
239
0
        mTimer = NS_NewTimer();
240
0
    }
241
0
242
0
    mTimer->InitWithCallback(this, aTimeout * 1000,
243
0
        nsITimer::TYPE_ONE_SHOT);
244
0
}
245
246
void
247
ConnectionData::StopTimer()
248
0
{
249
0
    if (mTimer) {
250
0
        mTimer->Cancel();
251
0
        mTimer = nullptr;
252
0
    }
253
0
}
254
255
256
class LookupHelper;
257
258
class LookupArgument
259
    : public nsISupports
260
{
261
0
    virtual ~LookupArgument() = default;
262
263
public:
264
    NS_DECL_THREADSAFE_ISUPPORTS
265
266
    LookupArgument(nsIDNSRecord *aRecord, LookupHelper *aHelper)
267
0
    {
268
0
        mRecord = aRecord;
269
0
        mHelper = aHelper;
270
0
    }
271
272
    nsCOMPtr<nsIDNSRecord> mRecord;
273
    RefPtr<LookupHelper> mHelper;
274
};
275
276
NS_IMPL_ISUPPORTS0(LookupArgument)
277
278
279
class LookupHelper final
280
    : public nsIDNSListener
281
{
282
    virtual ~LookupHelper()
283
0
    {
284
0
        if (mCancel) {
285
0
            mCancel->Cancel(NS_ERROR_ABORT);
286
0
        }
287
0
    }
288
289
public:
290
    NS_DECL_THREADSAFE_ISUPPORTS
291
    NS_DECL_NSIDNSLISTENER
292
293
    LookupHelper()
294
        : mEventTarget{ nullptr }
295
        , mStatus{ NS_ERROR_NOT_INITIALIZED }
296
0
    {
297
0
    }
298
299
    nsresult ConstructAnswer(LookupArgument *aArgument);
300
public:
301
    nsCOMPtr<nsICancelable> mCancel;
302
    nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
303
    nsIEventTarget *mEventTarget;
304
    nsresult mStatus;
305
};
306
307
NS_IMPL_ISUPPORTS(LookupHelper, nsIDNSListener)
308
309
NS_IMETHODIMP
310
LookupHelper::OnLookupComplete(nsICancelable *aRequest,
311
                               nsIDNSRecord *aRecord, nsresult aStatus)
312
0
{
313
0
    MOZ_ASSERT(aRequest == mCancel);
314
0
    mCancel = nullptr;
315
0
    mStatus = aStatus;
316
0
317
0
    RefPtr<LookupArgument> arg = new LookupArgument(aRecord, this);
318
0
    mEventTarget->Dispatch(NewRunnableMethod<RefPtr<LookupArgument>>
319
0
                           ("net::LookupHelper::ConstructAnswer",
320
0
                            this, &LookupHelper::ConstructAnswer, arg),
321
0
                           NS_DISPATCH_NORMAL);
322
0
323
0
    return NS_OK;
324
0
}
325
326
NS_IMETHODIMP
327
LookupHelper::OnLookupByTypeComplete(nsICancelable *aRequest,
328
                                     nsIDNSByTypeRecord *aRes,
329
                                     nsresult aStatus)
330
0
{
331
0
    return NS_OK;
332
0
}
333
334
nsresult
335
LookupHelper::ConstructAnswer(LookupArgument *aArgument)
336
0
{
337
0
    nsIDNSRecord *aRecord = aArgument->mRecord;
338
0
    AutoSafeJSContext cx;
339
0
340
0
    mozilla::dom::DNSLookupDict dict;
341
0
    dict.mAddress.Construct();
342
0
343
0
    Sequence<nsString> &addresses = dict.mAddress.Value();
344
0
345
0
    if (NS_SUCCEEDED(mStatus)) {
346
0
        dict.mAnswer = true;
347
0
        bool hasMore;
348
0
        aRecord->HasMore(&hasMore);
349
0
        while (hasMore) {
350
0
            nsString* nextAddress = addresses.AppendElement(fallible);
351
0
            if (!nextAddress) {
352
0
                return NS_ERROR_OUT_OF_MEMORY;
353
0
            }
354
0
355
0
            nsCString nextAddressASCII;
356
0
            aRecord->GetNextAddrAsString(nextAddressASCII);
357
0
            CopyASCIItoUTF16(nextAddressASCII, *nextAddress);
358
0
            aRecord->HasMore(&hasMore);
359
0
        }
360
0
    } else {
361
0
        dict.mAnswer = false;
362
0
        GetErrorString(mStatus, dict.mError);
363
0
    }
364
0
365
0
    JS::RootedValue val(cx);
366
0
    if (!ToJSValue(cx, dict, &val)) {
367
0
        return NS_ERROR_FAILURE;
368
0
    }
369
0
370
0
    this->mCallback->OnDashboardDataAvailable(val);
371
0
372
0
    return NS_OK;
373
0
}
374
375
NS_IMPL_ISUPPORTS(Dashboard, nsIDashboard, nsIDashboardEventNotifier)
376
377
Dashboard::Dashboard()
378
1
{
379
1
    mEnableLogging = false;
380
1
}
381
382
NS_IMETHODIMP
383
Dashboard::RequestSockets(NetDashboardCallback *aCallback)
384
0
{
385
0
    RefPtr<SocketData> socketData = new SocketData();
386
0
    socketData->mCallback =
387
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
388
0
          "NetDashboardCallback", aCallback, true);
389
0
    socketData->mEventTarget = GetCurrentThreadEventTarget();
390
0
    gSocketTransportService->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
391
0
              ("net::Dashboard::GetSocketsDispatch",
392
0
                                       this, &Dashboard::GetSocketsDispatch, socketData),
393
0
              NS_DISPATCH_NORMAL);
394
0
    return NS_OK;
395
0
}
396
397
nsresult
398
Dashboard::GetSocketsDispatch(SocketData *aSocketData)
399
0
{
400
0
    RefPtr<SocketData> socketData = aSocketData;
401
0
    if (gSocketTransportService) {
402
0
        gSocketTransportService->GetSocketConnections(&socketData->mData);
403
0
        socketData->mTotalSent = gSocketTransportService->GetSentBytes();
404
0
        socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes();
405
0
    }
406
0
    socketData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<SocketData>>
407
0
                                       ("net::Dashboard::GetSockets",
408
0
                                        this, &Dashboard::GetSockets, socketData),
409
0
                                       NS_DISPATCH_NORMAL);
410
0
    return NS_OK;
411
0
}
412
413
nsresult
414
Dashboard::GetSockets(SocketData *aSocketData)
415
0
{
416
0
    RefPtr<SocketData> socketData = aSocketData;
417
0
    AutoSafeJSContext cx;
418
0
419
0
    mozilla::dom::SocketsDict dict;
420
0
    dict.mSockets.Construct();
421
0
    dict.mSent = 0;
422
0
    dict.mReceived = 0;
423
0
424
0
    Sequence<mozilla::dom::SocketElement> &sockets = dict.mSockets.Value();
425
0
426
0
    uint32_t length = socketData->mData.Length();
427
0
    if (!sockets.SetCapacity(length, fallible)) {
428
0
            JS_ReportOutOfMemory(cx);
429
0
            return NS_ERROR_OUT_OF_MEMORY;
430
0
    }
431
0
432
0
    for (uint32_t i = 0; i < socketData->mData.Length(); i++) {
433
0
        dom::SocketElement &mSocket = *sockets.AppendElement(fallible);
434
0
        CopyASCIItoUTF16(socketData->mData[i].host, mSocket.mHost);
435
0
        mSocket.mPort = socketData->mData[i].port;
436
0
        mSocket.mActive = socketData->mData[i].active;
437
0
        mSocket.mTcp = socketData->mData[i].tcp;
438
0
        mSocket.mSent = (double) socketData->mData[i].sent;
439
0
        mSocket.mReceived = (double) socketData->mData[i].received;
440
0
        dict.mSent += socketData->mData[i].sent;
441
0
        dict.mReceived += socketData->mData[i].received;
442
0
    }
443
0
444
0
    dict.mSent += socketData->mTotalSent;
445
0
    dict.mReceived += socketData->mTotalRecv;
446
0
    JS::RootedValue val(cx);
447
0
    if (!ToJSValue(cx, dict, &val))
448
0
        return NS_ERROR_FAILURE;
449
0
    socketData->mCallback->OnDashboardDataAvailable(val);
450
0
451
0
    return NS_OK;
452
0
}
453
454
NS_IMETHODIMP
455
Dashboard::RequestHttpConnections(NetDashboardCallback *aCallback)
456
0
{
457
0
    RefPtr<HttpData> httpData = new HttpData();
458
0
    httpData->mCallback =
459
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
460
0
          "NetDashboardCallback", aCallback, true);
461
0
    httpData->mEventTarget = GetCurrentThreadEventTarget();
462
0
463
0
    gSocketTransportService->Dispatch(
464
0
      NewRunnableMethod<RefPtr<HttpData>>("net::Dashboard::GetHttpDispatch",
465
0
                                          this,
466
0
                                          &Dashboard::GetHttpDispatch,
467
0
                                          httpData),
468
0
      NS_DISPATCH_NORMAL);
469
0
    return NS_OK;
470
0
}
471
472
nsresult
473
Dashboard::GetHttpDispatch(HttpData *aHttpData)
474
0
{
475
0
    RefPtr<HttpData> httpData = aHttpData;
476
0
    HttpInfo::GetHttpConnectionData(&httpData->mData);
477
0
    httpData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<HttpData>>
478
0
                                     ("net::Dashboard::GetHttpConnections",
479
0
                                      this, &Dashboard::GetHttpConnections, httpData),
480
0
                                     NS_DISPATCH_NORMAL);
481
0
    return NS_OK;
482
0
}
483
484
485
nsresult
486
Dashboard::GetHttpConnections(HttpData *aHttpData)
487
0
{
488
0
    RefPtr<HttpData> httpData = aHttpData;
489
0
    AutoSafeJSContext cx;
490
0
491
0
    mozilla::dom::HttpConnDict dict;
492
0
    dict.mConnections.Construct();
493
0
494
0
    using mozilla::dom::HalfOpenInfoDict;
495
0
    using mozilla::dom::HttpConnectionElement;
496
0
    using mozilla::dom::HttpConnInfo;
497
0
    Sequence<HttpConnectionElement> &connections = dict.mConnections.Value();
498
0
499
0
    uint32_t length = httpData->mData.Length();
500
0
    if (!connections.SetCapacity(length, fallible)) {
501
0
            JS_ReportOutOfMemory(cx);
502
0
            return NS_ERROR_OUT_OF_MEMORY;
503
0
    }
504
0
505
0
    for (uint32_t i = 0; i < httpData->mData.Length(); i++) {
506
0
        HttpConnectionElement &connection = *connections.AppendElement(fallible);
507
0
508
0
        CopyASCIItoUTF16(httpData->mData[i].host, connection.mHost);
509
0
        connection.mPort = httpData->mData[i].port;
510
0
        connection.mSpdy = httpData->mData[i].spdy;
511
0
        connection.mSsl = httpData->mData[i].ssl;
512
0
513
0
        connection.mActive.Construct();
514
0
        connection.mIdle.Construct();
515
0
        connection.mHalfOpens.Construct();
516
0
517
0
        Sequence<HttpConnInfo> &active = connection.mActive.Value();
518
0
        Sequence<HttpConnInfo> &idle = connection.mIdle.Value();
519
0
        Sequence<HalfOpenInfoDict> &halfOpens = connection.mHalfOpens.Value();
520
0
521
0
        if (!active.SetCapacity(httpData->mData[i].active.Length(), fallible) ||
522
0
            !idle.SetCapacity(httpData->mData[i].idle.Length(), fallible) ||
523
0
            !halfOpens.SetCapacity(httpData->mData[i].halfOpens.Length(),
524
0
                                   fallible)) {
525
0
                JS_ReportOutOfMemory(cx);
526
0
                return NS_ERROR_OUT_OF_MEMORY;
527
0
        }
528
0
529
0
        for (uint32_t j = 0; j < httpData->mData[i].active.Length(); j++) {
530
0
            HttpConnInfo &info = *active.AppendElement(fallible);
531
0
            info.mRtt = httpData->mData[i].active[j].rtt;
532
0
            info.mTtl = httpData->mData[i].active[j].ttl;
533
0
            info.mProtocolVersion =
534
0
                httpData->mData[i].active[j].protocolVersion;
535
0
        }
536
0
537
0
        for (uint32_t j = 0; j < httpData->mData[i].idle.Length(); j++) {
538
0
            HttpConnInfo &info = *idle.AppendElement(fallible);
539
0
            info.mRtt = httpData->mData[i].idle[j].rtt;
540
0
            info.mTtl = httpData->mData[i].idle[j].ttl;
541
0
            info.mProtocolVersion = httpData->mData[i].idle[j].protocolVersion;
542
0
        }
543
0
544
0
        for (uint32_t j = 0; j < httpData->mData[i].halfOpens.Length(); j++) {
545
0
            HalfOpenInfoDict &info = *halfOpens.AppendElement(fallible);
546
0
            info.mSpeculative = httpData->mData[i].halfOpens[j].speculative;
547
0
        }
548
0
    }
549
0
550
0
    JS::RootedValue val(cx);
551
0
    if (!ToJSValue(cx, dict, &val)) {
552
0
        return NS_ERROR_FAILURE;
553
0
    }
554
0
555
0
    httpData->mCallback->OnDashboardDataAvailable(val);
556
0
557
0
    return NS_OK;
558
0
}
559
560
NS_IMETHODIMP
561
Dashboard::GetEnableLogging(bool *value)
562
0
{
563
0
    *value = mEnableLogging;
564
0
    return NS_OK;
565
0
}
566
567
NS_IMETHODIMP
568
Dashboard::SetEnableLogging(const bool value)
569
0
{
570
0
    mEnableLogging = value;
571
0
    return NS_OK;
572
0
}
573
574
NS_IMETHODIMP
575
Dashboard::AddHost(const nsACString& aHost, uint32_t aSerial, bool aEncrypted)
576
0
{
577
0
    if (mEnableLogging) {
578
0
        mozilla::MutexAutoLock lock(mWs.lock);
579
0
        LogData mData(nsCString(aHost), aSerial, aEncrypted);
580
0
        if (mWs.data.Contains(mData)) {
581
0
            return NS_OK;
582
0
        }
583
0
        if (!mWs.data.AppendElement(mData)) {
584
0
            return NS_ERROR_OUT_OF_MEMORY;
585
0
        }
586
0
        return NS_OK;
587
0
    }
588
0
    return NS_ERROR_FAILURE;
589
0
}
590
591
NS_IMETHODIMP
592
Dashboard::RemoveHost(const nsACString& aHost, uint32_t aSerial)
593
0
{
594
0
    if (mEnableLogging) {
595
0
        mozilla::MutexAutoLock lock(mWs.lock);
596
0
        int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
597
0
        if (index == -1)
598
0
            return NS_ERROR_FAILURE;
599
0
        mWs.data.RemoveElementAt(index);
600
0
        return NS_OK;
601
0
    }
602
0
    return NS_ERROR_FAILURE;
603
0
}
604
605
NS_IMETHODIMP
606
Dashboard::NewMsgSent(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
607
0
{
608
0
    if (mEnableLogging) {
609
0
        mozilla::MutexAutoLock lock(mWs.lock);
610
0
        int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
611
0
        if (index == -1)
612
0
            return NS_ERROR_FAILURE;
613
0
        mWs.data[index].mMsgSent++;
614
0
        mWs.data[index].mSizeSent += aLength;
615
0
        return NS_OK;
616
0
    }
617
0
    return NS_ERROR_FAILURE;
618
0
}
619
620
NS_IMETHODIMP
621
Dashboard::NewMsgReceived(const nsACString& aHost, uint32_t aSerial, uint32_t aLength)
622
0
{
623
0
    if (mEnableLogging) {
624
0
        mozilla::MutexAutoLock lock(mWs.lock);
625
0
        int32_t index = mWs.IndexOf(nsCString(aHost), aSerial);
626
0
        if (index == -1)
627
0
            return NS_ERROR_FAILURE;
628
0
        mWs.data[index].mMsgReceived++;
629
0
        mWs.data[index].mSizeReceived += aLength;
630
0
        return NS_OK;
631
0
    }
632
0
    return NS_ERROR_FAILURE;
633
0
}
634
635
NS_IMETHODIMP
636
Dashboard::RequestWebsocketConnections(NetDashboardCallback *aCallback)
637
0
{
638
0
    RefPtr<WebSocketRequest> wsRequest = new WebSocketRequest();
639
0
    wsRequest->mCallback =
640
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
641
0
          "NetDashboardCallback", aCallback, true);
642
0
    wsRequest->mEventTarget = GetCurrentThreadEventTarget();
643
0
644
0
    wsRequest->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<WebSocketRequest>>
645
0
                                      ("net::Dashboard::GetWebSocketConnections",
646
0
                                       this, &Dashboard::GetWebSocketConnections, wsRequest),
647
0
                                      NS_DISPATCH_NORMAL);
648
0
    return NS_OK;
649
0
}
650
651
nsresult
652
Dashboard::GetWebSocketConnections(WebSocketRequest *aWsRequest)
653
0
{
654
0
    RefPtr<WebSocketRequest> wsRequest = aWsRequest;
655
0
    AutoSafeJSContext cx;
656
0
657
0
    mozilla::dom::WebSocketDict dict;
658
0
    dict.mWebsockets.Construct();
659
0
    Sequence<mozilla::dom::WebSocketElement> &websockets =
660
0
        dict.mWebsockets.Value();
661
0
662
0
    mozilla::MutexAutoLock lock(mWs.lock);
663
0
    uint32_t length = mWs.data.Length();
664
0
    if (!websockets.SetCapacity(length, fallible)) {
665
0
        JS_ReportOutOfMemory(cx);
666
0
        return NS_ERROR_OUT_OF_MEMORY;
667
0
    }
668
0
669
0
    for (uint32_t i = 0; i < mWs.data.Length(); i++) {
670
0
        dom::WebSocketElement &websocket = *websockets.AppendElement(fallible);
671
0
        CopyASCIItoUTF16(mWs.data[i].mHost, websocket.mHostport);
672
0
        websocket.mMsgsent = mWs.data[i].mMsgSent;
673
0
        websocket.mMsgreceived = mWs.data[i].mMsgReceived;
674
0
        websocket.mSentsize = mWs.data[i].mSizeSent;
675
0
        websocket.mReceivedsize = mWs.data[i].mSizeReceived;
676
0
        websocket.mEncrypted = mWs.data[i].mEncrypted;
677
0
    }
678
0
679
0
    JS::RootedValue val(cx);
680
0
    if (!ToJSValue(cx, dict, &val)) {
681
0
        return NS_ERROR_FAILURE;
682
0
    }
683
0
    wsRequest->mCallback->OnDashboardDataAvailable(val);
684
0
685
0
    return NS_OK;
686
0
}
687
688
NS_IMETHODIMP
689
Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback)
690
0
{
691
0
    RefPtr<DnsData> dnsData = new DnsData();
692
0
    dnsData->mCallback =
693
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
694
0
          "NetDashboardCallback", aCallback, true);
695
0
696
0
    nsresult rv;
697
0
    dnsData->mData.Clear();
698
0
    dnsData->mEventTarget = GetCurrentThreadEventTarget();
699
0
700
0
    if (!mDnsService) {
701
0
        mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
702
0
        if (NS_FAILED(rv)) {
703
0
            return rv;
704
0
        }
705
0
    }
706
0
707
0
    gSocketTransportService->Dispatch(
708
0
      NewRunnableMethod<RefPtr<DnsData>>("net::Dashboard::GetDnsInfoDispatch",
709
0
                                         this,
710
0
                                         &Dashboard::GetDnsInfoDispatch,
711
0
                                         dnsData),
712
0
      NS_DISPATCH_NORMAL);
713
0
    return NS_OK;
714
0
}
715
716
nsresult
717
Dashboard::GetDnsInfoDispatch(DnsData *aDnsData)
718
0
{
719
0
    RefPtr<DnsData> dnsData = aDnsData;
720
0
    if (mDnsService) {
721
0
        mDnsService->GetDNSCacheEntries(&dnsData->mData);
722
0
    }
723
0
    dnsData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<DnsData>>
724
0
                                    ("net::Dashboard::GetDNSCacheEntries",
725
0
                                     this, &Dashboard::GetDNSCacheEntries, dnsData),
726
0
                                    NS_DISPATCH_NORMAL);
727
0
    return NS_OK;
728
0
}
729
730
nsresult
731
Dashboard::GetDNSCacheEntries(DnsData *dnsData)
732
0
{
733
0
    AutoSafeJSContext cx;
734
0
735
0
    mozilla::dom::DNSCacheDict dict;
736
0
    dict.mEntries.Construct();
737
0
    Sequence<mozilla::dom::DnsCacheEntry> &entries = dict.mEntries.Value();
738
0
739
0
    uint32_t length = dnsData->mData.Length();
740
0
    if (!entries.SetCapacity(length, fallible)) {
741
0
        JS_ReportOutOfMemory(cx);
742
0
        return NS_ERROR_OUT_OF_MEMORY;
743
0
    }
744
0
745
0
    for (uint32_t i = 0; i < dnsData->mData.Length(); i++) {
746
0
        dom::DnsCacheEntry &entry = *entries.AppendElement(fallible);
747
0
        entry.mHostaddr.Construct();
748
0
749
0
        Sequence<nsString> &addrs = entry.mHostaddr.Value();
750
0
        if (!addrs.SetCapacity(dnsData->mData[i].hostaddr.Length(), fallible)) {
751
0
            JS_ReportOutOfMemory(cx);
752
0
            return NS_ERROR_OUT_OF_MEMORY;
753
0
        }
754
0
755
0
        CopyASCIItoUTF16(dnsData->mData[i].hostname, entry.mHostname);
756
0
        entry.mExpiration = dnsData->mData[i].expiration;
757
0
        entry.mTrr = dnsData->mData[i].TRR;
758
0
759
0
        for (uint32_t j = 0; j < dnsData->mData[i].hostaddr.Length(); j++) {
760
0
            nsString* addr = addrs.AppendElement(fallible);
761
0
            if (!addr) {
762
0
                JS_ReportOutOfMemory(cx);
763
0
                return NS_ERROR_OUT_OF_MEMORY;
764
0
            }
765
0
            CopyASCIItoUTF16(dnsData->mData[i].hostaddr[j], *addr);
766
0
        }
767
0
768
0
        if (dnsData->mData[i].family == PR_AF_INET6) {
769
0
            entry.mFamily.AssignLiteral(u"ipv6");
770
0
        } else {
771
0
            entry.mFamily.AssignLiteral(u"ipv4");
772
0
        }
773
0
    }
774
0
775
0
    JS::RootedValue val(cx);
776
0
    if (!ToJSValue(cx, dict, &val)) {
777
0
        return NS_ERROR_FAILURE;
778
0
    }
779
0
    dnsData->mCallback->OnDashboardDataAvailable(val);
780
0
781
0
    return NS_OK;
782
0
}
783
784
NS_IMETHODIMP
785
Dashboard::RequestDNSLookup(const nsACString &aHost,
786
                            NetDashboardCallback *aCallback)
787
0
{
788
0
    nsresult rv;
789
0
790
0
    if (!mDnsService) {
791
0
        mDnsService = do_GetService("@mozilla.org/network/dns-service;1", &rv);
792
0
        if (NS_FAILED(rv)) {
793
0
            return rv;
794
0
        }
795
0
    }
796
0
797
0
    RefPtr<LookupHelper> helper = new LookupHelper();
798
0
    helper->mCallback =
799
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
800
0
          "NetDashboardCallback", aCallback, true);
801
0
    helper->mEventTarget = GetCurrentThreadEventTarget();
802
0
    OriginAttributes attrs;
803
0
    rv = mDnsService->AsyncResolveNative(aHost, 0, helper.get(),
804
0
                                         NS_GetCurrentThread(), attrs,
805
0
                                         getter_AddRefs(helper->mCancel));
806
0
    return rv;
807
0
}
808
809
NS_IMETHODIMP
810
Dashboard::RequestRcwnStats(NetDashboardCallback *aCallback)
811
0
{
812
0
    RefPtr<RcwnData> rcwnData = new RcwnData();
813
0
    rcwnData->mEventTarget = GetCurrentThreadEventTarget();
814
0
    rcwnData->mCallback =
815
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
816
0
          "NetDashboardCallback", aCallback, true);
817
0
818
0
    return rcwnData->mEventTarget->Dispatch(
819
0
      NewRunnableMethod<RefPtr<RcwnData>>("net::Dashboard::GetRcwnData",
820
0
                                          this, &Dashboard::GetRcwnData, rcwnData),
821
0
        NS_DISPATCH_NORMAL);
822
0
}
823
824
nsresult
825
Dashboard::GetRcwnData(RcwnData *aData)
826
0
{
827
0
    AutoSafeJSContext cx;
828
0
    mozilla::dom::RcwnStatus dict;
829
0
830
0
    dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber();
831
0
    dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
832
0
    dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
833
0
834
0
    uint32_t cacheSlow, cacheNotSlow;
835
0
    CacheFileUtils::CachePerfStats::GetSlowStats(&cacheSlow, &cacheNotSlow);
836
0
    dict.mCacheSlowCount = cacheSlow;
837
0
    dict.mCacheNotSlowCount = cacheNotSlow;
838
0
839
0
    dict.mPerfStats.Construct();
840
0
    Sequence<mozilla::dom::RcwnPerfStats> &perfStats = dict.mPerfStats.Value();
841
0
    uint32_t length = CacheFileUtils::CachePerfStats::LAST;
842
0
    if (!perfStats.SetCapacity(length, fallible)) {
843
0
        JS_ReportOutOfMemory(cx);
844
0
        return NS_ERROR_OUT_OF_MEMORY;
845
0
    }
846
0
847
0
    for (uint32_t i = 0; i < length; i++) {
848
0
        CacheFileUtils::CachePerfStats::EDataType perfType =
849
0
            static_cast<CacheFileUtils::CachePerfStats::EDataType>(i);
850
0
        dom::RcwnPerfStats &elem = *perfStats.AppendElement(fallible);
851
0
        elem.mAvgShort = CacheFileUtils::CachePerfStats::GetAverage(perfType, false);
852
0
        elem.mAvgLong = CacheFileUtils::CachePerfStats::GetAverage(perfType, true);
853
0
        elem.mStddevLong = CacheFileUtils::CachePerfStats::GetStdDev(perfType, true);
854
0
    }
855
0
856
0
    JS::RootedValue val(cx);
857
0
    if (!ToJSValue(cx, dict, &val)) {
858
0
        return NS_ERROR_FAILURE;
859
0
    }
860
0
861
0
    aData->mCallback->OnDashboardDataAvailable(val);
862
0
863
0
    return NS_OK;
864
0
}
865
866
void
867
HttpConnInfo::SetHTTP1ProtocolVersion(HttpVersion pv)
868
{
869
    switch (pv) {
870
    case HttpVersion::v0_9:
871
        protocolVersion.AssignLiteral(u"http/0.9");
872
        break;
873
    case HttpVersion::v1_0:
874
        protocolVersion.AssignLiteral(u"http/1.0");
875
        break;
876
    case HttpVersion::v1_1:
877
        protocolVersion.AssignLiteral(u"http/1.1");
878
        break;
879
    case HttpVersion::v2_0:
880
        protocolVersion.AssignLiteral(u"http/2.0");
881
        break;
882
    default:
883
        protocolVersion.AssignLiteral(u"unknown protocol version");
884
    }
885
}
886
887
void
888
HttpConnInfo::SetHTTP2ProtocolVersion(SpdyVersion pv)
889
0
{
890
0
    MOZ_ASSERT(pv == SpdyVersion::HTTP_2);
891
0
    protocolVersion.AssignLiteral(u"h2");
892
0
}
893
894
NS_IMETHODIMP
895
Dashboard::GetLogPath(nsACString &aLogPath)
896
0
{
897
0
    aLogPath.SetLength(2048);
898
0
    uint32_t len = LogModule::GetLogFile(aLogPath.BeginWriting(), 2048);
899
0
    aLogPath.SetLength(len);
900
0
    return NS_OK;
901
0
}
902
903
NS_IMETHODIMP
904
Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort,
905
                             const char *aProtocol, uint32_t aTimeout,
906
                             NetDashboardCallback *aCallback)
907
0
{
908
0
    nsresult rv;
909
0
    RefPtr<ConnectionData> connectionData = new ConnectionData(this);
910
0
    connectionData->mHost = aHost;
911
0
    connectionData->mPort = aPort;
912
0
    connectionData->mProtocol = aProtocol;
913
0
    connectionData->mTimeout = aTimeout;
914
0
915
0
    connectionData->mCallback =
916
0
        new nsMainThreadPtrHolder<NetDashboardCallback>(
917
0
          "NetDashboardCallback", aCallback, true);
918
0
    connectionData->mEventTarget = GetCurrentThreadEventTarget();
919
0
920
0
    rv = TestNewConnection(connectionData);
921
0
    if (NS_FAILED(rv)) {
922
0
        mozilla::net::GetErrorString(rv, connectionData->mStatus);
923
0
        connectionData->mEventTarget->Dispatch(NewRunnableMethod<RefPtr<ConnectionData>>
924
0
                                               ("net::Dashboard::GetConnectionStatus",
925
0
                                                this, &Dashboard::GetConnectionStatus, connectionData),
926
0
                                               NS_DISPATCH_NORMAL);
927
0
        return rv;
928
0
    }
929
0
930
0
    return NS_OK;
931
0
}
932
933
nsresult
934
Dashboard::GetConnectionStatus(ConnectionData *aConnectionData)
935
0
{
936
0
    RefPtr<ConnectionData> connectionData = aConnectionData;
937
0
    AutoSafeJSContext cx;
938
0
939
0
    mozilla::dom::ConnStatusDict dict;
940
0
    dict.mStatus = connectionData->mStatus;
941
0
942
0
    JS::RootedValue val(cx);
943
0
    if (!ToJSValue(cx, dict, &val))
944
0
        return NS_ERROR_FAILURE;
945
0
946
0
    connectionData->mCallback->OnDashboardDataAvailable(val);
947
0
948
0
    return NS_OK;
949
0
}
950
951
nsresult
952
Dashboard::TestNewConnection(ConnectionData *aConnectionData)
953
0
{
954
0
    RefPtr<ConnectionData> connectionData = aConnectionData;
955
0
956
0
    nsresult rv;
957
0
    if (!connectionData->mHost.Length() ||
958
0
        !net_IsValidHostName(connectionData->mHost)) {
959
0
        return NS_ERROR_UNKNOWN_HOST;
960
0
    }
961
0
962
0
    if (connectionData->mProtocol &&
963
0
        NS_LITERAL_STRING("ssl").EqualsASCII(connectionData->mProtocol)) {
964
0
        rv = gSocketTransportService->CreateTransport(
965
0
            &connectionData->mProtocol, 1, connectionData->mHost,
966
0
            connectionData->mPort, nullptr,
967
0
            getter_AddRefs(connectionData->mSocket));
968
0
    } else {
969
0
        rv = gSocketTransportService->CreateTransport(
970
0
            nullptr, 0, connectionData->mHost,
971
0
            connectionData->mPort, nullptr,
972
0
            getter_AddRefs(connectionData->mSocket));
973
0
    }
974
0
    if (NS_FAILED(rv)) {
975
0
        return rv;
976
0
    }
977
0
978
0
    rv = connectionData->mSocket->SetEventSink(connectionData,
979
0
        GetCurrentThreadEventTarget());
980
0
    if (NS_FAILED(rv)) {
981
0
        return rv;
982
0
    }
983
0
984
0
    rv = connectionData->mSocket->OpenInputStream(
985
0
        nsITransport::OPEN_BLOCKING, 0, 0,
986
0
        getter_AddRefs(connectionData->mStreamIn));
987
0
    if (NS_FAILED(rv)) {
988
0
        return rv;
989
0
    }
990
0
991
0
    connectionData->StartTimer(connectionData->mTimeout);
992
0
993
0
    return rv;
994
0
}
995
996
typedef struct
997
{
998
    nsresult key;
999
    const char *error;
1000
} ErrorEntry;
1001
1002
#undef ERROR
1003
#define ERROR(key, val) {key, #key}
1004
1005
ErrorEntry socketTransportStatuses[] = {
1006
        ERROR(NS_NET_STATUS_RESOLVING_HOST,         FAILURE(3)),
1007
        ERROR(NS_NET_STATUS_RESOLVED_HOST,          FAILURE(11)),
1008
        ERROR(NS_NET_STATUS_CONNECTING_TO,          FAILURE(7)),
1009
        ERROR(NS_NET_STATUS_CONNECTED_TO,           FAILURE(4)),
1010
        ERROR(NS_NET_STATUS_TLS_HANDSHAKE_STARTING, FAILURE(12)),
1011
        ERROR(NS_NET_STATUS_TLS_HANDSHAKE_ENDED,    FAILURE(13)),
1012
        ERROR(NS_NET_STATUS_SENDING_TO,             FAILURE(5)),
1013
        ERROR(NS_NET_STATUS_WAITING_FOR,            FAILURE(10)),
1014
        ERROR(NS_NET_STATUS_RECEIVING_FROM,         FAILURE(6)),
1015
};
1016
#undef ERROR
1017
1018
1019
static void
1020
GetErrorString(nsresult rv, nsAString& errorString)
1021
0
{
1022
0
    for (auto& socketTransportStatus : socketTransportStatuses) {
1023
0
        if (socketTransportStatus.key == rv) {
1024
0
            errorString.AssignASCII(socketTransportStatus.error);
1025
0
            return;
1026
0
        }
1027
0
    }
1028
0
    nsAutoCString errorCString;
1029
0
    mozilla::GetErrorName(rv, errorCString);
1030
0
    CopyUTF8toUTF16(errorCString, errorString);
1031
0
}
1032
1033
} // namespace net
1034
} // namespace mozilla