Bug 1053650 - Part 2: Populate networkInterfaceId to SocketTransport. r=mcmanus, a=bajaj
authorHenry Chang <hchang@mozilla.com>
Tue, 07 Apr 2015 11:45:57 -0400
changeset 238136 4a91d189b58c3d1e92a1b272c9ae651b42780a02
parent 238135 c09519f7f74c2227e0194a7c58e7c5d8f0bf53f8
child 238137 dc0fce2633ddbf39143a98344af36155afc900a9
push id488
push userryanvm@gmail.com
push dateMon, 13 Apr 2015 20:29:57 +0000
treeherdermozilla-b2g37_v2_2@85ea1be9ac7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmcmanus, bajaj
bugs1053650
milestone37.0
Bug 1053650 - Part 2: Populate networkInterfaceId to SocketTransport. r=mcmanus, a=bajaj
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnectionInfo.cpp
netwerk/protocol/http/nsHttpConnectionInfo.h
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsIHttpChannelInternal.idl
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -889,16 +889,31 @@ HttpBaseChannel::SetRequestMethod(const 
   if (!nsHttp::IsValidToken(flatMethod))
     return NS_ERROR_INVALID_ARG;
 
   mRequestHead.SetMethod(flatMethod);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+HttpBaseChannel::GetNetworkInterfaceId(nsACString& aNetworkInterfaceId)
+{
+  aNetworkInterfaceId = mNetworkInterfaceId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpBaseChannel::SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId)
+{
+  ENSURE_CALLED_BEFORE_CONNECT();
+  mNetworkInterfaceId = aNetworkInterfaceId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpBaseChannel::GetReferrer(nsIURI **referrer)
 {
   NS_ENSURE_ARG_POINTER(referrer);
   *referrer = mReferrer;
   NS_IF_ADDREF(*referrer);
   return NS_OK;
 }
 
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -183,16 +183,18 @@ public:
   NS_IMETHOD TakeAllSecurityMessages(nsCOMArray<nsISecurityConsoleMessage> &aMessages) MOZ_OVERRIDE;
   NS_IMETHOD GetResponseTimeoutEnabled(bool *aEnable) MOZ_OVERRIDE;
   NS_IMETHOD SetResponseTimeoutEnabled(bool aEnable) MOZ_OVERRIDE;
   NS_IMETHOD AddRedirect(nsIPrincipal *aRedirect) MOZ_OVERRIDE;
   NS_IMETHOD ForcePending(bool aForcePending) MOZ_OVERRIDE;
   NS_IMETHOD GetLastModifiedTime(PRTime* lastModifiedTime) MOZ_OVERRIDE;
   NS_IMETHOD ForceNoIntercept() MOZ_OVERRIDE;
   NS_IMETHOD GetTopWindowURI(nsIURI **aTopWindowURI) MOZ_OVERRIDE;
+  NS_IMETHOD GetNetworkInterfaceId(nsACString& aNetworkInterfaceId) MOZ_OVERRIDE;
+  NS_IMETHOD SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId) MOZ_OVERRIDE;
 
   inline void CleanRedirectCacheChainIfNecessary()
   {
       mRedirectedCachekeys = nullptr;
   }
   NS_IMETHOD HTTPUpgrade(const nsACString & aProtocolName,
                          nsIHttpUpgradeListener *aListener) MOZ_OVERRIDE;
 
@@ -408,16 +410,19 @@ protected:
   // copied from the transaction before we null out mTransaction
   // so that the timing can still be queried from OnStopRequest
   TimingStruct                      mTransactionTimings;
 
   nsCOMPtr<nsIPrincipal>            mPrincipal;
 
   bool                              mForcePending;
   nsCOMPtr<nsIURI>                  mTopWindowURI;
+
+  // The network interface id that's associated with this channel.
+  nsCString mNetworkInterfaceId;
 };
 
 // Share some code while working around C++'s absurd inability to handle casting
 // of member functions between base/derived types.
 // - We want to store member function pointer to call at resume time, but one
 //   such function--HandleAsyncAbort--we want to share between the
 //   nsHttpChannel/HttpChannelChild.  Can't define it in base class, because
 //   then we'd have to cast member function ptr between base/derived class
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -4846,16 +4846,22 @@ nsHttpChannel::BeginConnect()
         Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC, true);
         Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC_OE, !isHttps);
     } else {
         LOG(("nsHttpChannel %p Using default connection info", this));
         mConnectionInfo = new nsHttpConnectionInfo(host, port, EmptyCString(), mUsername, proxyInfo, isHttps);
         Telemetry::Accumulate(Telemetry::HTTP_TRANSACTION_USE_ALTSVC, false);
     }
 
+    // Set network interface id only when it's not empty to avoid
+    // rebuilding hash key.
+    if (!mNetworkInterfaceId.IsEmpty()) {
+        mConnectionInfo->SetNetworkInterfaceId(mNetworkInterfaceId);
+    }
+
     mAuthProvider =
         do_CreateInstance("@mozilla.org/network/http-channel-auth-provider;1",
                           &rv);
     if (NS_SUCCEEDED(rv))
         rv = mAuthProvider->Init(this);
     if (NS_FAILED(rv))
         return rv;
 
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -75,21 +75,24 @@ nsHttpConnectionInfo::Init(const nsACStr
             mUsingConnect = true;
         }
     }
 
     SetOriginServer(host, port);
 }
 
 void
-nsHttpConnectionInfo::SetOriginServer(const nsACString &host, int32_t port)
+nsHttpConnectionInfo::SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId)
 {
-    mHost = host;
-    mPort = port == -1 ? DefaultPort() : port;
+    mNetworkInterfaceId = aNetworkInterfaceId;
+    BuildHashKey();
+}
 
+void nsHttpConnectionInfo::BuildHashKey()
+{
     //
     // build hash key:
     //
     // the hash key uniquely identifies the connection type.  two connections
     // are "equal" if they end up talking the same protocol to the same server
     // and are both used for anonymous or non-anonymous connection only;
     // anonymity of the connection is setup later from nsHttpChannel::AsyncOpen
     // where we know we use anonymous connection (LOAD_ANONYMOUS load flag)
@@ -111,16 +114,21 @@ nsHttpConnectionInfo::SetOriginServer(co
     // byte 1 is S/. S is for end to end ssl such as https:// uris
     // byte 2 is A/. A is for an anonymous channel (no cookies, etc..)
     // byte 3 is P/. P is for a private browising channel
     // byte 4 is R/. R is for 'relaxed' unauthed TLS for http:// uris
     // byte 5 is X/. X is for disallow_spdy flag
 
     mHashKey.AssignLiteral("......");
     mHashKey.Append(keyHost);
+    if (!mNetworkInterfaceId.IsEmpty()) {
+        mHashKey.Append('(');
+        mHashKey.Append(mNetworkInterfaceId);
+        mHashKey.Append(')');
+    }
     mHashKey.Append(':');
     mHashKey.AppendInt(keyPort);
     if (!mUsername.IsEmpty()) {
         mHashKey.Append('[');
         mHashKey.Append(mUsername);
         mHashKey.Append(']');
     }
 
@@ -164,29 +172,41 @@ nsHttpConnectionInfo::SetOriginServer(co
 
     if (!mNPNToken.IsEmpty()) {
         mHashKey.AppendLiteral(" {NPN-TOKEN ");
         mHashKey.Append(mNPNToken);
         mHashKey.AppendLiteral("}");
     }
 }
 
+void
+nsHttpConnectionInfo::SetOriginServer(const nsACString &host, int32_t port)
+{
+    mHost = host;
+    mPort = port == -1 ? DefaultPort() : port;
+    BuildHashKey();
+}
+
 nsHttpConnectionInfo*
 nsHttpConnectionInfo::Clone() const
 {
     nsHttpConnectionInfo *clone;
     if (mAuthenticationHost.IsEmpty()) {
         clone = new nsHttpConnectionInfo(mHost, mPort, mNPNToken, mUsername, mProxyInfo, mEndToEndSSL);
     } else {
         MOZ_ASSERT(mEndToEndSSL);
         clone = new nsHttpConnectionInfo(mHost, mPort, mNPNToken, mUsername, mProxyInfo,
                                          mAuthenticationHost,
                                          mAuthenticationPort);
     }
 
+    if (!mNetworkInterfaceId.IsEmpty()) {
+        clone->SetNetworkInterfaceId(mNetworkInterfaceId);
+    }
+
     // Make sure the anonymous, relaxed, and private flags are transferred
     clone->SetAnonymous(GetAnonymous());
     clone->SetPrivate(GetPrivate());
     clone->SetRelaxed(GetRelaxed());
     clone->SetNoSpdy(GetNoSpdy());
     MOZ_ASSERT(clone->Equals(this));
 
     return clone;
@@ -203,16 +223,19 @@ nsHttpConnectionInfo::CloneAsDirectRoute
     nsRefPtr<nsHttpConnectionInfo> clone =
         new nsHttpConnectionInfo(mAuthenticationHost, mAuthenticationPort,
                                  EmptyCString(), mUsername, mProxyInfo, mEndToEndSSL);
     // Make sure the anonymous, relaxed, and private flags are transferred
     clone->SetAnonymous(GetAnonymous());
     clone->SetPrivate(GetPrivate());
     clone->SetRelaxed(GetRelaxed());
     clone->SetNoSpdy(GetNoSpdy());
+    if (!mNetworkInterfaceId.IsEmpty()) {
+        clone->SetNetworkInterfaceId(mNetworkInterfaceId);
+    }
     clone.forget(outCI);
 }
 
 nsresult
 nsHttpConnectionInfo::CreateWildCard(nsHttpConnectionInfo **outParam)
 {
     // T???mozilla.org:443 (https:proxy.ducksong.com:3128) [specifc form]
     // TS??*:0 (https:proxy.ducksong.com:3128)   [wildcard form]
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -50,22 +50,29 @@ public:
                          int32_t logicalPort);
 
 private:
     virtual ~nsHttpConnectionInfo()
     {
         PR_LOG(gHttpLog, 4, ("Destroying nsHttpConnectionInfo @%x\n", this));
     }
 
+    void BuildHashKey();
+
 public:
     const nsAFlatCString &HashKey() const { return mHashKey; }
 
     const nsCString &GetAuthenticationHost() const { return mAuthenticationHost; }
     int32_t GetAuthenticationPort() const { return mAuthenticationPort; }
 
+    // With overhead rebuilding the hash key. The initial
+    // network interface is empty. So you can reduce one call
+    // if there's no explicit route after ctor.
+    void SetNetworkInterfaceId(const nsACString& aNetworkInterfaceId);
+
     // OK to treat these as an infalible allocation
     nsHttpConnectionInfo* Clone() const;
     void CloneAsDirectRoute(nsHttpConnectionInfo **outParam);
     nsresult CreateWildCard(nsHttpConnectionInfo **outParam);
 
     const char *ProxyHost() const { return mProxyInfo ? mProxyInfo->Host().get() : nullptr; }
     int32_t     ProxyPort() const { return mProxyInfo ? mProxyInfo->Port() : -1; }
     const char *ProxyType() const { return mProxyInfo ? mProxyInfo->Type() : nullptr; }
@@ -95,16 +102,18 @@ public:
     void          SetRelaxed(bool relaxed)
                                        { mHashKey.SetCharAt(relaxed ? 'R' : '.', 4); }
     bool          GetRelaxed() const   { return mHashKey.CharAt(4) == 'R'; }
 
     void          SetNoSpdy(bool aNoSpdy)
                                        { mHashKey.SetCharAt(aNoSpdy ? 'X' : '.', 5); }
     bool          GetNoSpdy() const    { return mHashKey.CharAt(5) == 'X'; }
 
+    const nsCString &GetNetworkInterfaceId() const { return mNetworkInterfaceId; }
+
     const nsCString &GetHost() { return mHost; }
     const nsCString &GetNPNToken() { return mNPNToken; }
 
     // Returns true for any kind of proxy (http, socks, https, etc..)
     bool UsingProxy();
 
     // Returns true when proxying over HTTP or HTTPS
     bool UsingHttpProxy() const { return mUsingHttpProxy || mUsingHttpsProxy; }
@@ -130,16 +139,17 @@ private:
               const nsACString &npnToken,
               const nsACString &username,
               nsProxyInfo* proxyInfo,
               bool EndToEndSSL);
     void SetOriginServer(const nsACString &host, int32_t port);
 
     nsCString              mHashKey;
     nsCString              mHost;
+    nsCString              mNetworkInterfaceId;
     int32_t                mPort;
     nsCString              mUsername;
     nsCString              mAuthenticationHost;
     int32_t                mAuthenticationPort;
     nsCOMPtr<nsProxyInfo>  mProxyInfo;
     bool                   mUsingHttpProxy;
     bool                   mUsingHttpsProxy;
     bool                   mEndToEndSSL;
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3117,16 +3117,20 @@ nsHalfOpenSocket::SetupStreams(nsISocket
     if (!Allow1918()) {
         tmpFlags |= nsISocketTransport::DISABLE_RFC1918;
     }
 
     socketTransport->SetConnectionFlags(tmpFlags);
 
     socketTransport->SetQoSBits(gHttpHandler->GetQoSBits());
 
+    if (!mEnt->mConnInfo->GetNetworkInterfaceId().IsEmpty()) {
+        socketTransport->SetNetworkInterfaceId(mEnt->mConnInfo->GetNetworkInterfaceId());
+    }
+
     rv = socketTransport->SetEventSink(this, nullptr);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = socketTransport->SetSecurityCallbacks(this);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIOutputStream> sout;
     rv = socketTransport->OpenOutputStream(nsITransport::OPEN_UNBUFFERED,
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -33,17 +33,17 @@ interface nsIHttpUpgradeListener : nsISu
                               in nsIAsyncOutputStream aSocketOut);
 };
 
 /**
  * Dumping ground for http.  This interface will never be frozen.  If you are
  * using any feature exposed by this interface, be aware that this interface
  * will change and you will be broken.  You have been warned.
  */
-[scriptable, uuid(bbf9d5bb-8daf-4909-88bc-f3b2f6a886d0)]
+[scriptable, uuid(ad8192a1-668e-4a47-bd77-081eb23e50fa)]
 interface nsIHttpChannelInternal : nsISupports
 {
     /**
      * An http channel can own a reference to the document URI
      */
     attribute nsIURI documentURI;
 
     /**
@@ -216,12 +216,17 @@ interface nsIHttpChannelInternal : nsISu
 
     /**
      * Force a channel that has not been AsyncOpen'ed to skip any check for possible
      * interception and proceed immediately to the network/cache.
      */
     void forceNoIntercept();
 
     /**
+     * The network interface id that's associated with this channel.
+     */
+    attribute ACString networkInterfaceId;
+
+    /**
      * The URI of the top-level window that's associated with this channel.
      */
     readonly attribute nsIURI topWindowURI;
 };