Bug 1363700 - Add RCWN stats to about:networking r=michal
MozReview-Commit-ID: GVt1omCfL6t
--- a/dom/webidl/NetDashboard.webidl
+++ b/dom/webidl/NetDashboard.webidl
@@ -70,8 +70,14 @@ dictionary DNSLookupDict {
sequence<DOMString> address;
DOMString error = "";
boolean answer = false;
};
dictionary ConnStatusDict {
DOMString status = "";
};
+
+dictionary RcwnStatus {
+ unsigned long totalNetworkRequests = 0;
+ unsigned long rcwnCacheWonCount = 0;
+ unsigned long rcwnNetWonCount = 0;
+};
--- a/netwerk/base/Dashboard.cpp
+++ b/netwerk/base/Dashboard.cpp
@@ -14,16 +14,17 @@
#include "nsIInputStream.h"
#include "nsISocketTransport.h"
#include "nsIThread.h"
#include "nsProxyRelease.h"
#include "nsSocketTransportService2.h"
#include "nsThreadUtils.h"
#include "nsURLHelper.h"
#include "mozilla/Logging.h"
+#include "nsIOService.h"
using mozilla::AutoSafeJSContext;
using mozilla::dom::Sequence;
using mozilla::dom::ToJSValue;
namespace mozilla {
namespace net {
@@ -162,16 +163,38 @@ public:
const char *mProtocol;
uint32_t mTimeout;
nsString mStatus;
};
NS_IMPL_ISUPPORTS(ConnectionData, nsITransportEventSink, nsITimerCallback)
+
+class RcwnData
+ : public nsISupports
+{
+ virtual ~RcwnData()
+ {
+ }
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ RcwnData()
+ {
+ mThread = nullptr;
+ }
+
+ nsMainThreadPtrHandle<NetDashboardCallback> mCallback;
+ nsIThread *mThread;
+};
+
+NS_IMPL_ISUPPORTS0(RcwnData)
+
NS_IMETHODIMP
ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus,
int64_t aProgress, int64_t aProgressMax)
{
if (aStatus == NS_NET_STATUS_CONNECTED_TO) {
StopTimer();
}
@@ -750,16 +773,49 @@ Dashboard::RequestDNSLookup(const nsACSt
helper->mThread = NS_GetCurrentThread();
OriginAttributes attrs;
rv = mDnsService->AsyncResolveNative(aHost, 0, helper.get(),
NS_GetCurrentThread(), attrs,
getter_AddRefs(helper->mCancel));
return rv;
}
+NS_IMETHODIMP
+Dashboard::RequestRcwnStats(NetDashboardCallback *aCallback)
+{
+ RefPtr<RcwnData> rcwnData = new RcwnData();
+ rcwnData->mThread = NS_GetCurrentThread();
+ rcwnData->mCallback =
+ new nsMainThreadPtrHolder<NetDashboardCallback>(aCallback, true);
+
+ return rcwnData->mThread->Dispatch(
+ NewRunnableMethod<RefPtr<RcwnData>>(this, &Dashboard::GetRcwnData, rcwnData),
+ NS_DISPATCH_NORMAL);
+}
+
+nsresult
+Dashboard::GetRcwnData(RcwnData *aData)
+{
+ AutoSafeJSContext cx;
+ mozilla::dom::RcwnStatus dict;
+
+ dict.mTotalNetworkRequests = gIOService->GetTotalRequestNumber();
+ dict.mRcwnCacheWonCount = gIOService->GetCacheWonRequestNumber();
+ dict.mRcwnNetWonCount = gIOService->GetNetWonRequestNumber();
+
+ JS::RootedValue val(cx);
+ if (!ToJSValue(cx, dict, &val)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ aData->mCallback->OnDashboardDataAvailable(val);
+
+ return NS_OK;
+}
+
void
HttpConnInfo::SetHTTP1ProtocolVersion(uint8_t pv)
{
switch (pv) {
case NS_HTTP_VERSION_0_9:
protocolVersion.AssignLiteral(u"http/0.9");
break;
case NS_HTTP_VERSION_1_0:
--- a/netwerk/base/Dashboard.h
+++ b/netwerk/base/Dashboard.h
@@ -19,16 +19,17 @@ class nsIDNSService;
namespace mozilla {
namespace net {
class SocketData;
class HttpData;
class DnsData;
class WebSocketRequest;
class ConnectionData;
+class RcwnData;
class Dashboard final
: public nsIDashboard
, public nsIDashboardEventNotifier
{
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDASHBOARD
@@ -90,16 +91,17 @@ private:
nsresult GetDnsInfoDispatch(DnsData *);
nsresult TestNewConnection(ConnectionData *);
/* Helper methods that pass the JSON to the callback function. */
nsresult GetSockets(SocketData *);
nsresult GetHttpConnections(HttpData *);
nsresult GetDNSCacheEntries(DnsData *);
nsresult GetWebSocketConnections(WebSocketRequest *);
+ nsresult GetRcwnData(RcwnData *);
nsCOMPtr<nsIDNSService> mDnsService;
};
} // namespace net
} // namespace mozilla
#endif // nsDashboard_h__
--- a/netwerk/base/nsIDashboard.idl
+++ b/netwerk/base/nsIDashboard.idl
@@ -45,10 +45,15 @@ interface nsIDashboard : nsISupports
/* When true, the service will log websocket events */
attribute boolean enableLogging;
/* DNS resolver for host name
* aHost: host name */
void requestDNSLookup(in ACString aHost, in NetDashboardCallback cb);
+ /**
+ * Asyncly returns stats regarding the "Race Cache With Network" feature.
+ */
+ void requestRcwnStats(in NetDashboardCallback cb);
+
AUTF8String getLogPath();
};
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -183,16 +183,19 @@ nsIOService::nsIOService()
, mOfflineMirrorsConnectivity(true)
, mSettingOffline(false)
, mSetOfflineValue(false)
, mShutdown(false)
, mHttpHandlerAlreadyShutingDown(false)
, mNetworkLinkServiceInitialized(false)
, mChannelEventSinks(NS_CHANNEL_EVENT_SINK_CATEGORY)
, mNetworkNotifyChanged(true)
+ , mTotalRequests(0)
+ , mCacheWon(0)
+ , mNetWon(0)
, mLastOfflineStateChange(PR_IntervalNow())
, mLastConnectivityChange(PR_IntervalNow())
, mLastNetworkLinkChange(PR_IntervalNow())
, mNetTearingDownStarted(0)
{
}
nsresult
--- a/netwerk/base/nsIOService.h
+++ b/netwerk/base/nsIOService.h
@@ -92,16 +92,25 @@ public:
// As soon as nsIOService gets notification that it is shutdown it is going to
// reset mHttpHandlerAlreadyShutingDown.
void SetHttpHandlerAlreadyShutingDown();
bool IsLinkUp();
static bool IsInheritSecurityContextForDataURIEnabled();
+ // Used to count the total number of HTTP requests made
+ void IncrementRequestNumber() { mTotalRequests++; }
+ uint32_t GetTotalRequestNumber() { return mTotalRequests; }
+ // Used to keep "race cache with network" stats
+ void IncrementCacheWonRequestNumber() { mCacheWon++; }
+ uint32_t GetCacheWonRequestNumber() { return mCacheWon; }
+ void IncrementNetWonRequestNumber() { mNetWon++; }
+ uint32_t GetNetWonRequestNumber() { return mNetWon; }
+
// Used to trigger a recheck of the captive portal status
nsresult RecheckCaptivePortal();
private:
// These shouldn't be called directly:
// - construct using GetInstance
// - destroy using Release
nsIOService();
~nsIOService();
@@ -173,16 +182,20 @@ private:
nsCategoryCache<nsIChannelEventSink> mChannelEventSinks;
nsTArray<int32_t> mRestrictedPortList;
bool mNetworkNotifyChanged;
static bool sDataURIInheritSecurityContext;
+ uint32_t mTotalRequests;
+ uint32_t mCacheWon;
+ uint32_t mNetWon;
+
// These timestamps are needed for collecting telemetry on PR_Connect,
// PR_ConnectContinue and PR_Close blocking time. If we spend very long
// time in any of these functions we want to know if and what network
// change has happened shortly before.
mozilla::Atomic<PRIntervalTime> mLastOfflineStateChange;
mozilla::Atomic<PRIntervalTime> mLastConnectivityChange;
mozilla::Atomic<PRIntervalTime> mLastNetworkLinkChange;
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -7239,16 +7239,23 @@ nsHttpChannel::OnStopRequest(nsIRequest
nsresult rv = FinalizeCacheEntry();
if (NS_FAILED(rv)) {
LOG(("FinalizeCacheEntry failed (%08x)",
static_cast<uint32_t>(rv)));
}
}
}
+ gIOService->IncrementRequestNumber();
+ if (rcwnStatus == kRaceUsedCache) {
+ gIOService->IncrementCacheWonRequestNumber();
+ } else if (rcwnStatus == kRaceUsedNetwork) {
+ gIOService->IncrementNetWonRequestNumber();
+ }
+
// Register entry to the Performance resource timing
mozilla::dom::Performance* documentPerformance = GetPerformance();
if (documentPerformance) {
documentPerformance->AddEntry(this, this);
}
if (mListener) {
LOG((" calling OnStopRequest\n"));
--- a/toolkit/content/aboutNetworking.js
+++ b/toolkit/content/aboutNetworking.js
@@ -16,23 +16,25 @@ const gDashboard = Cc["@mozilla.org/netw
.getService(Ci.nsIDashboard);
const gDirServ = Cc["@mozilla.org/file/directory_service;1"]
.getService(Ci.nsIDirectoryServiceProvider);
const gRequestNetworkingData = {
"http": gDashboard.requestHttpConnections,
"sockets": gDashboard.requestSockets,
"dns": gDashboard.requestDNSInfo,
- "websockets": gDashboard.requestWebsocketConnections
+ "websockets": gDashboard.requestWebsocketConnections,
+ "rcwn": gDashboard.requestRcwnStats,
};
const gDashboardCallbacks = {
"http": displayHttp,
"sockets": displaySockets,
"dns": displayDns,
- "websockets": displayWebsockets
+ "websockets": displayWebsockets,
+ "rcwn": displayRcwnStats,
};
const REFRESH_INTERVAL_MS = 3000;
function col(element) {
let col = document.createElement("td");
let content = document.createTextNode(element);
col.appendChild(content);
@@ -119,16 +121,28 @@ function displayWebsockets(data) {
row.appendChild(col(data.websockets[i].sentsize));
row.appendChild(col(data.websockets[i].receivedsize));
new_cont.appendChild(row);
}
parent.replaceChild(new_cont, cont);
}
+function displayRcwnStats(data) {
+ let status = Services.prefs.getBoolPref("network.http.rcwn.enabled");
+ let cacheWon = data.rcwnCacheWonCount;
+ let netWon = data.rcwnNetWonCount;
+ let total = data.totalNetworkRequests;
+
+ document.getElementById("rcwn_status").innerText = status;
+ document.getElementById("total_req_count").innerText = total;
+ document.getElementById("rcwn_cache_won_count").innerText = cacheWon;
+ document.getElementById("rcwn_cache_net_count").innerText = netWon;
+}
+
function requestAllNetworkingData() {
for (let id in gRequestNetworkingData)
requestNetworkingDataForTab(id);
}
function requestNetworkingDataForTab(id) {
gRequestNetworkingData[id](gDashboardCallbacks[id]);
}
--- a/toolkit/content/aboutNetworking.xhtml
+++ b/toolkit/content/aboutNetworking.xhtml
@@ -45,16 +45,19 @@
</div>
<hr></hr>
<div class="category" value="dnslookuptool">
<span class="category-name">&aboutNetworking.dnsLookup;</span>
</div>
<div class="category" value="logging">
<span class="category-name">&aboutNetworking.logging;</span>
</div>
+ <div class="category" value="rcwn">
+ <span class="category-name">&aboutNetworking.rcwn;</span>
+ </div>
</div>
<div class="main-content">
<div class="header">
<div id="sectionTitle" class="header-name">
&aboutNetworking.HTTP;
</div>
<div id="refreshDiv" class="toggle-container-with-text">
<button id="refreshButton">&aboutNetworking.refresh;</button>
@@ -134,16 +137,37 @@
<tr>
<th>&aboutNetworking.dnsLookupTableColumn;</th>
</tr>
</thead>
<tbody id="dnslookuptool_content" />
</table>
</div>
+ <div id="rcwn" class="tab" hidden="true">
+ <table>
+ <thead>
+ <tr>
+ <th>&aboutNetworking.rcwnStatus;</th>
+ <th>&aboutNetworking.totalNetworkRequests;</th>
+ <th>&aboutNetworking.rcwnCacheWonCount;</th>
+ <th>&aboutNetworking.rcwnNetWonCount;</th>
+ </tr>
+ </thead>
+ <tbody id="rcwn_content">
+ <tr>
+ <td id="rcwn_status"> </td>
+ <td id="total_req_count"> </td>
+ <td id="rcwn_cache_won_count"> </td>
+ <td id="rcwn_cache_net_count"> </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
<div id="logging" class="tab" hidden="true">
<div>
&aboutNetworking.logTutorial;
</div>
<br/>
<div>
<button id="start-logging-button"> &aboutNetworking.startLogging; </button>
<button id="stop-logging-button"> &aboutNetworking.stopLogging; </button>
--- a/toolkit/locales/en-US/chrome/global/aboutNetworking.dtd
+++ b/toolkit/locales/en-US/chrome/global/aboutNetworking.dtd
@@ -36,8 +36,13 @@
<!ENTITY aboutNetworking.setLogFile "Set Log File">
<!ENTITY aboutNetworking.setLogModules "Set Log Modules">
<!ENTITY aboutNetworking.startLogging "Start Logging">
<!ENTITY aboutNetworking.stopLogging "Stop Logging">
<!ENTITY aboutNetworking.dnsLookup "DNS Lookup">
<!ENTITY aboutNetworking.dnsLookupButton "Resolve">
<!ENTITY aboutNetworking.dnsDomain "Domain">
<!ENTITY aboutNetworking.dnsLookupTableColumn "IPs">
+<!ENTITY aboutNetworking.rcwn "RCWN Stats">
+<!ENTITY aboutNetworking.rcwnStatus "RCWN Status">
+<!ENTITY aboutNetworking.rcwnCacheWonCount "Cache won count">
+<!ENTITY aboutNetworking.rcwnNetWonCount "Net won count">
+<!ENTITY aboutNetworking.totalNetworkRequests "Total network request count">