bug 805457 telemetry for proxy and websocket connections r=jduell
authorPatrick McManus <mcmanus@ducksong.com>
Sat, 27 Oct 2012 15:24:19 -0400
changeset 111751 b9f9c4a12b50ba4f6f88762a2c34b85568711990
parent 111750 7426b782e0b9494109079eb11d915b65cb0e4f58
child 111752 eb63fc7d719deab06e883895248be80ecbe379aa
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersjduell
bugs805457
milestone19.0a1
bug 805457 telemetry for proxy and websocket connections r=jduell
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpConnectionMgr.h
netwerk/protocol/websocket/WebSocketChannel.cpp
netwerk/protocol/websocket/WebSocketChannel.h
toolkit/components/telemetry/Histograms.json
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -1665,16 +1665,29 @@ nsHttpConnectionMgr::BuildPipeline(nsCon
        on a nsHttpPipeline object is not a real HTTP pipeline */
    
     nsRefPtr<nsHttpPipeline> pipeline = new nsHttpPipeline();
     pipeline->AddTransaction(firstTrans);
     NS_ADDREF(*result = pipeline);
     return NS_OK;
 }
 
+void
+nsHttpConnectionMgr::ReportProxyTelemetry(nsConnectionEntry *ent)
+{
+    enum { PROXY_NONE = 1, PROXY_HTTP = 2, PROXY_SOCKS = 3 };
+
+    if (!ent->mConnInfo->UsingProxy())
+        Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_NONE);
+    else if (ent->mConnInfo->UsingHttpProxy())
+        Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_HTTP);
+    else
+        Telemetry::Accumulate(Telemetry::HTTP_PROXY_TYPE, PROXY_SOCKS);
+}
+
 nsresult
 nsHttpConnectionMgr::ProcessNewTransaction(nsHttpTransaction *trans)
 {
     NS_ABORT_IF_FALSE(PR_GetCurrentThread() == gSocketThread, "wrong thread");
 
     // since "adds" and "cancels" are processed asynchronously and because
     // various events might trigger an "add" directly on the socket thread,
     // we must take care to avoid dispatching a transaction that has already
@@ -1698,16 +1711,18 @@ nsHttpConnectionMgr::ProcessNewTransacti
     if (preferredEntry && (preferredEntry != ent)) {
         LOG(("nsHttpConnectionMgr::ProcessNewTransaction trans=%p "
              "redirected via coalescing from %s to %s\n", trans,
              ent->mConnInfo->Host(), preferredEntry->mConnInfo->Host()));
 
         ent = preferredEntry;
     }
 
+    ReportProxyTelemetry(ent);
+
     // If we are doing a force reload then close out any existing conns
     // to this host so that changes in DNS, LBs, etc.. are reflected
     if (trans->Caps() & NS_HTTP_CLEAR_KEEPALIVES)
         ClosePersistentConnections(ent);
 
     // Check if the transaction already has a sticky reference to a connection.
     // If so, then we can just use it directly by transferring its reference
     // to the new connection variable instead of searching for a new one
--- a/netwerk/protocol/http/nsHttpConnectionMgr.h
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.h
@@ -476,16 +476,17 @@ private:
                                          int32_t);
     nsresult BuildPipeline(nsConnectionEntry *,
                            nsAHttpTransaction *,
                            nsHttpPipeline **);
     bool     RestrictConnections(nsConnectionEntry *);
     nsresult ProcessNewTransaction(nsHttpTransaction *);
     nsresult EnsureSocketThreadTarget();
     void     ClosePersistentConnections(nsConnectionEntry *ent);
+    void     ReportProxyTelemetry(nsConnectionEntry *ent);
     nsresult CreateTransport(nsConnectionEntry *, nsAHttpTransaction *,
                              uint8_t, bool);
     void     AddActiveConn(nsHttpConnection *, nsConnectionEntry *);
     void     StartedConnect();
     void     RecvdConnect();
 
     nsConnectionEntry *GetOrCreateConnectionEntry(nsHttpConnectionInfo *);
 
--- a/netwerk/protocol/websocket/WebSocketChannel.cpp
+++ b/netwerk/protocol/websocket/WebSocketChannel.cpp
@@ -15,31 +15,34 @@
 #include "nsIPrefBranch.h"
 #include "nsIPrefService.h"
 #include "nsICancelable.h"
 #include "nsIDNSRecord.h"
 #include "nsIDNSService.h"
 #include "nsIStreamConverterService.h"
 #include "nsIIOService2.h"
 #include "nsIProtocolProxyService.h"
+#include "nsIProxyInfo.h"
+#include "nsIProxiedChannel.h"
 
 #include "nsAutoPtr.h"
 #include "nsStandardURL.h"
 #include "nsNetCID.h"
 #include "nsServiceManagerUtils.h"
 #include "nsXPIDLString.h"
 #include "nsCRT.h"
 #include "nsThreadUtils.h"
 #include "nsError.h"
 #include "nsStringStream.h"
 #include "nsAlgorithm.h"
 #include "nsProxyRelease.h"
 #include "nsNetUtil.h"
 #include "mozilla/Attributes.h"
 #include "TimeStamp.h"
+#include "mozilla/Telemetry.h"
 
 #include "plbase64.h"
 #include "prmem.h"
 #include "prnetdb.h"
 #include "prbit.h"
 #include "zlib.h"
 
 // rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
@@ -912,17 +915,17 @@ private:
 WebSocketChannel::WebSocketChannel() :
   mPort(0),
   mCloseTimeout(20000),
   mOpenTimeout(20000),
   mConnecting(NOT_CONNECTING),
   mPingTimeout(0),
   mPingResponseTimeout(10000),
   mMaxConcurrentConnections(200),
-  mRecvdHttpOnStartRequest(0),
+  mGotUpgradeOK(0),
   mRecvdHttpUpgradeTransport(0),
   mRequestedClose(0),
   mClientClosed(0),
   mServerClosed(0),
   mStopped(0),
   mCalledOnStop(0),
   mPingOutstanding(0),
   mAllowCompression(1),
@@ -2182,16 +2185,46 @@ WebSocketChannel::StartWebsocketData()
        mListener.get()));
 
   if (mListener)
     mListener->OnStart(mContext);
 
   return mSocketIn->AsyncWait(this, 0, 0, mSocketThread);
 }
 
+void
+WebSocketChannel::ReportConnectionTelemetry()
+{ 
+  // 3 bits are used. high bit is for wss, middle bit for failed,
+  // and low bit for proxy..
+  // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
+  //         wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
+
+  bool didProxy = false;
+
+  nsCOMPtr<nsIProxyInfo> pi;
+  nsCOMPtr<nsIProxiedChannel> pc = do_QueryInterface(mChannel);
+  if (pc)
+    pc->GetProxyInfo(getter_AddRefs(pi));
+  if (pi) {
+    nsAutoCString proxyType;
+    pi->GetType(proxyType);
+    if (!proxyType.IsEmpty() &&
+        !proxyType.Equals(NS_LITERAL_CSTRING("direct")))
+      didProxy = true;
+  }
+
+  uint8_t value = (mEncrypted ? (1 << 2) : 0) | 
+    (!mGotUpgradeOK ? (1 << 1) : 0) |
+    (didProxy ? (1 << 0) : 0);
+
+  LOG(("WebSocketChannel::ReportConnectionTelemetry() %p %d", this, value));
+  Telemetry::Accumulate(Telemetry::WEBSOCKETS_HANDSHAKE_TYPE, value);
+}
+
 // nsIDNSListener
 
 NS_IMETHODIMP
 WebSocketChannel::OnLookupComplete(nsICancelable *aRequest,
                                      nsIDNSRecord *aRecord,
                                      nsresult aStatus)
 {
   LOG(("WebSocketChannel::OnLookupComplete() %p [%p %p %x]\n",
@@ -2375,17 +2408,17 @@ WebSocketChannel::Notify(nsITimer *timer
 
     mCloseTimer = nullptr;
     if (mStopped || mServerClosed)                /* no longer relevant */
       return NS_OK;
 
     LOG(("WebSocketChannel:: Expecting Server Close - Timed Out\n"));
     AbortSession(NS_ERROR_NET_TIMEOUT);
   } else if (timer == mOpenTimer) {
-    NS_ABORT_IF_FALSE(!mRecvdHttpOnStartRequest,
+    NS_ABORT_IF_FALSE(!mGotUpgradeOK,
                       "Open Timer after open complete");
     NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
     mOpenTimer = nullptr;
     LOG(("WebSocketChannel:: Connection Timed Out\n"));
     if (mStopped || mServerClosed)                /* no longer relevant */
       return NS_OK;
 
@@ -2712,48 +2745,48 @@ WebSocketChannel::OnTransportAvailable(n
   if (!NS_IsMainThread()) {
     return NS_DispatchToMainThread(new CallOnTransportAvailable(this,
                                                                 aTransport,
                                                                 aSocketIn,
                                                                 aSocketOut));
   }
 
   LOG(("WebSocketChannel::OnTransportAvailable %p [%p %p %p] rcvdonstart=%d\n",
-       this, aTransport, aSocketIn, aSocketOut, mRecvdHttpOnStartRequest));
+       this, aTransport, aSocketIn, aSocketOut, mGotUpgradeOK));
 
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
   NS_ABORT_IF_FALSE(!mRecvdHttpUpgradeTransport, "OTA duplicated");
   NS_ABORT_IF_FALSE(aSocketIn, "OTA with invalid socketIn");
 
   mTransport = aTransport;
   mSocketIn = aSocketIn;
   mSocketOut = aSocketOut;
 
   nsresult rv;
   rv = mTransport->SetEventSink(nullptr, nullptr);
   if (NS_FAILED(rv)) return rv;
   rv = mTransport->SetSecurityCallbacks(this);
   if (NS_FAILED(rv)) return rv;
 
   mRecvdHttpUpgradeTransport = 1;
-  if (mRecvdHttpOnStartRequest)
+  if (mGotUpgradeOK)
     return StartWebsocketData();
   return NS_OK;
 }
 
 // nsIRequestObserver (from nsIStreamListener)
 
 NS_IMETHODIMP
 WebSocketChannel::OnStartRequest(nsIRequest *aRequest,
                                  nsISupports *aContext)
 {
   LOG(("WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n",
        this, aRequest, aContext, mRecvdHttpUpgradeTransport));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
-  NS_ABORT_IF_FALSE(!mRecvdHttpOnStartRequest, "OTA duplicated");
+  NS_ABORT_IF_FALSE(!mGotUpgradeOK, "OTA duplicated");
 
   if (mOpenTimer) {
     mOpenTimer->Cancel();
     mOpenTimer = nullptr;
   }
 
   if (mStopped) {
     LOG(("WebSocketChannel::OnStartRequest: Channel Already Done\n"));
@@ -2876,32 +2909,34 @@ WebSocketChannel::OnStartRequest(nsIRequ
       mProtocol.Truncate();
     }
   }
 
   rv = HandleExtensions();
   if (NS_FAILED(rv))
     return rv;
 
-  mRecvdHttpOnStartRequest = 1;
+  mGotUpgradeOK = 1;
   if (mRecvdHttpUpgradeTransport)
     return StartWebsocketData();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 WebSocketChannel::OnStopRequest(nsIRequest *aRequest,
                                   nsISupports *aContext,
                                   nsresult aStatusCode)
 {
   LOG(("WebSocketChannel::OnStopRequest() %p [%p %p %x]\n",
        this, aRequest, aContext, aStatusCode));
   NS_ABORT_IF_FALSE(NS_IsMainThread(), "not main thread");
 
+  ReportConnectionTelemetry();
+
   // This is the end of the HTTP upgrade transaction, the
   // upgraded streams live on
 
   mChannel = nullptr;
   mHttpChannel = nullptr;
   mLoadGroup = nullptr;
   mCallbacks = nullptr;
 
--- a/netwerk/protocol/websocket/WebSocketChannel.h
+++ b/netwerk/protocol/websocket/WebSocketChannel.h
@@ -127,16 +127,17 @@ private:
   void GeneratePing();
 
   void     BeginOpen();
   nsresult HandleExtensions();
   nsresult SetupRequest();
   nsresult ApplyForAdmission();
   nsresult StartWebsocketData();
   uint16_t ResultToCloseCode(nsresult resultCode);
+  void     ReportConnectionTelemetry();
 
   void StopSession(nsresult reason);
   void AbortSession(nsresult reason);
   void ReleaseSession();
   void CleanupConnection();
   void IncrementSessionCount();
   void DecrementSessionCount();
 
@@ -181,17 +182,17 @@ private:
   uint32_t                        mPingResponseTimeout;  /* milliseconds */
 
   nsCOMPtr<nsITimer>              mLingeringCloseTimer;
   const static int32_t            kLingeringCloseTimeout =   1000;
   const static int32_t            kLingeringCloseThreshold = 50;
 
   int32_t                         mMaxConcurrentConnections;
 
-  uint32_t                        mRecvdHttpOnStartRequest   : 1;
+  uint32_t                        mGotUpgradeOK              : 1;
   uint32_t                        mRecvdHttpUpgradeTransport : 1;
   uint32_t                        mRequestedClose            : 1;
   uint32_t                        mClientClosed              : 1;
   uint32_t                        mServerClosed              : 1;
   uint32_t                        mStopped                   : 1;
   uint32_t                        mCalledOnStop              : 1;
   uint32_t                        mPingOutstanding           : 1;
   uint32_t                        mAllowCompression          : 1;
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -696,16 +696,26 @@
     "description": "HTTP subitem: Overall load time - cache hits (ms)"
   },
   "HTTP_SUB_COMPLETE_LOAD_NET": {
     "kind": "exponential",
     "high": "30000",
     "n_buckets": 50,
     "description": "HTTP subitem: Overall load time - network (ms)"
   },
+  "HTTP_PROXY_TYPE": {
+    "kind": "enumerated",
+    "n_values": 8,
+    "description": "HTTP Proxy Type (none, http, socks)"
+  },
+  "WEBSOCKETS_HANDSHAKE_TYPE": {
+    "kind": "enumerated",
+    "n_values": 16,
+    "description": "Websockets Handshake Results (ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy, wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy)"
+  },
   "SPDY_VERSION2": {
     "kind": "enumerated",
     "n_values": 48,
     "description": "SPDY: Protocol Version Used"
   },
   "SPDY_PARALLEL_STREAMS": {
     "kind": "exponential",
     "high": "1000",