Bug 1502025 - Add NS_HTTP_DISABLE_IPV4 and NS_HTTP_DISABLE_IPV6 flags r=dragana
authorValentin Gosu <valentin.gosu@gmail.com>
Sun, 02 Dec 2018 23:28:52 +0000
changeset 505619 e18883f3328eb3d949fb7458005d84b2e2bbad3c
parent 505618 6cbbac93c27318820e9a626a25aced587ef3a010
child 505620 552ef6767e3b9244a8f31382306f3ffa42bdb2de
push id10290
push userffxbld-merge
push dateMon, 03 Dec 2018 16:23:23 +0000
treeherdermozilla-beta@700bed2445e6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdragana
bugs1502025
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1502025 - Add NS_HTTP_DISABLE_IPV4 and NS_HTTP_DISABLE_IPV6 flags r=dragana Differential Revision: https://phabricator.services.mozilla.com/D13332
netwerk/protocol/http/HttpBaseChannel.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/TrackingDummyChannel.cpp
netwerk/protocol/http/nsHttp.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
netwerk/protocol/viewsource/nsViewSourceChannel.cpp
--- a/netwerk/protocol/http/HttpBaseChannel.cpp
+++ b/netwerk/protocol/http/HttpBaseChannel.cpp
@@ -4503,10 +4503,14 @@ HttpBaseChannel::GetNativeServerTiming(
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HttpBaseChannel::CancelForTrackingProtection() {
   return Cancel(NS_ERROR_TRACKING_URI);
 }
 
+void HttpBaseChannel::SetIPv4Disabled() { mCaps |= NS_HTTP_DISABLE_IPV4; }
+
+void HttpBaseChannel::SetIPv6Disabled() { mCaps |= NS_HTTP_DISABLE_IPV6; }
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -298,16 +298,18 @@ class HttpBaseChannel : public nsHashPro
       nsACString &aConnectionInfoHashKey) override;
   NS_IMETHOD GetIntegrityMetadata(nsAString &aIntegrityMetadata) override;
   NS_IMETHOD SetIntegrityMetadata(const nsAString &aIntegrityMetadata) override;
   NS_IMETHOD GetLastRedirectFlags(uint32_t *aValue) override;
   NS_IMETHOD SetLastRedirectFlags(uint32_t aValue) override;
   NS_IMETHOD GetNavigationStartTimeStamp(TimeStamp *aTimeStamp) override;
   NS_IMETHOD SetNavigationStartTimeStamp(TimeStamp aTimeStamp) override;
   NS_IMETHOD CancelForTrackingProtection() override;
+  virtual void SetIPv4Disabled(void) override;
+  virtual void SetIPv6Disabled(void) override;
 
   inline void CleanRedirectCacheChainIfNecessary() {
     mRedirectedCachekeys = nullptr;
   }
   NS_IMETHOD HTTPUpgrade(const nsACString &aProtocolName,
                          nsIHttpUpgradeListener *aListener) override;
 
   // nsISupportsPriority
--- a/netwerk/protocol/http/TrackingDummyChannel.cpp
+++ b/netwerk/protocol/http/TrackingDummyChannel.cpp
@@ -621,10 +621,14 @@ TrackingDummyChannel::SetNavigationStart
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
 NS_IMETHODIMP
 TrackingDummyChannel::CancelForTrackingProtection() {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
+void TrackingDummyChannel::SetIPv4Disabled() {}
+
+void TrackingDummyChannel::SetIPv6Disabled() {}
+
 }  // namespace net
 }  // namespace mozilla
--- a/netwerk/protocol/http/nsHttp.h
+++ b/netwerk/protocol/http/nsHttp.h
@@ -116,16 +116,22 @@ enum class SpdyVersion {
 // without accidentally allowing it for websockets not over http/2
 #define NS_HTTP_ALLOW_SPDY_WITHOUT_KEEPALIVE (1 << 15)
 
 // Only permit CONNECTing to a proxy. A channel with this flag will not send an
 // http request after CONNECT or setup tls. An http upgrade handler MUST be
 // set. An ALPN header is set using the upgrade protocol.
 #define NS_HTTP_CONNECT_ONLY (1 << 16)
 
+// The connection should not use IPv4.
+#define NS_HTTP_DISABLE_IPV4 (1 << 17)
+
+// The connection should not use IPv6
+#define NS_HTTP_DISABLE_IPV6 (1 << 18)
+
 //-----------------------------------------------------------------------------
 // some default values
 //-----------------------------------------------------------------------------
 
 #define NS_HTTP_DEFAULT_PORT 80
 #define NS_HTTPS_DEFAULT_PORT 443
 
 #define NS_HTTP_HEADER_SEPS ", \t"
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -560,16 +560,18 @@ nsresult nsHttpChannel::OnBeforeConnect(
   mConnectionInfo->SetAnonymous((mLoadFlags & LOAD_ANONYMOUS) != 0);
   mConnectionInfo->SetPrivate(mPrivateBrowsing);
   mConnectionInfo->SetNoSpdy(mCaps & NS_HTTP_DISALLOW_SPDY);
   mConnectionInfo->SetBeConservative((mCaps & NS_HTTP_BE_CONSERVATIVE) ||
                                      mBeConservative);
   mConnectionInfo->SetTlsFlags(mTlsFlags);
   mConnectionInfo->SetTrrUsed(mTRR);
   mConnectionInfo->SetTrrDisabled(mCaps & NS_HTTP_DISABLE_TRR);
+  mConnectionInfo->SetIPv4Disabled(mCaps & NS_HTTP_DISABLE_IPV4);
+  mConnectionInfo->SetIPv6Disabled(mCaps & NS_HTTP_DISABLE_IPV6);
 
   // notify "http-on-before-connect" observers
   gHttpHandler->OnBeforeConnect(this);
 
   // Check if request was cancelled during http-on-before-connect.
   if (mCanceled) {
     return mStatus;
   }
@@ -808,17 +810,18 @@ void nsHttpChannel::SpeculativeConnect()
 
   nsCOMPtr<nsIInterfaceRequestor> callbacks;
   NS_NewNotificationCallbacksAggregation(mCallbacks, mLoadGroup,
                                          getter_AddRefs(callbacks));
   if (!callbacks) return;
 
   Unused << gHttpHandler->SpeculativeConnect(
       mConnectionInfo, callbacks,
-      mCaps & (NS_HTTP_DISALLOW_SPDY | NS_HTTP_DISABLE_TRR));
+      mCaps & (NS_HTTP_DISALLOW_SPDY | NS_HTTP_DISABLE_TRR |
+               NS_HTTP_DISABLE_IPV4 | NS_HTTP_DISABLE_IPV6));
 }
 
 void nsHttpChannel::DoNotifyListenerCleanup() {
   // We don't need this info anymore
   CleanRedirectCacheChainIfNecessary();
 }
 
 void nsHttpChannel::ReleaseListeners() {
--- a/netwerk/protocol/http/nsHttpConnectionInfo.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.cpp
@@ -78,16 +78,18 @@ void nsHttpConnectionInfo::Init(const ns
   mProxyInfo = proxyInfo;
   mEndToEndSSL = e2eSSL;
   mUsingConnect = false;
   mNPNToken = npnToken;
   mOriginAttributes = originAttributes;
   mTlsFlags = 0x0;
   mTrrUsed = false;
   mTrrDisabled = false;
+  mIPv4Disabled = false;
+  mIPv6Disabled = false;
 
   mUsingHttpsProxy = (proxyInfo && proxyInfo->IsHTTPS());
   mUsingHttpProxy = mUsingHttpsProxy || (proxyInfo && proxyInfo->IsHTTP());
 
   if (mUsingHttpProxy) {
     mUsingConnect = mEndToEndSSL;  // SSL always uses CONNECT
     uint32_t resolveFlags = 0;
     if (NS_SUCCEEDED(mProxyInfo->GetResolveFlags(&resolveFlags)) &&
@@ -203,16 +205,24 @@ void nsHttpConnectionInfo::BuildHashKey(
 
   if (GetTrrDisabled()) {
     // When connecting with TRR disabled, we enforce a separate connection
     // hashkey so that we also can trigger a fresh DNS resolver that then
     // doesn't use TRR as the previous connection might have.
     mHashKey.AppendLiteral("[NOTRR]");
   }
 
+  if (GetIPv4Disabled()) {
+    mHashKey.AppendLiteral("[!v4]");
+  }
+
+  if (GetIPv6Disabled()) {
+    mHashKey.AppendLiteral("[!v6]");
+  }
+
   nsAutoCString originAttributes;
   mOriginAttributes.CreateSuffix(originAttributes);
   mHashKey.Append(originAttributes);
 }
 
 void nsHttpConnectionInfo::SetOriginServer(const nsACString &host,
                                            int32_t port) {
   mOrigin = host;
@@ -237,16 +247,18 @@ nsHttpConnectionInfo *nsHttpConnectionIn
   clone->SetAnonymous(GetAnonymous());
   clone->SetPrivate(GetPrivate());
   clone->SetInsecureScheme(GetInsecureScheme());
   clone->SetNoSpdy(GetNoSpdy());
   clone->SetBeConservative(GetBeConservative());
   clone->SetTlsFlags(GetTlsFlags());
   clone->SetTrrUsed(GetTrrUsed());
   clone->SetTrrDisabled(GetTrrDisabled());
+  clone->SetIPv4Disabled(GetIPv4Disabled());
+  clone->SetIPv6Disabled(GetIPv6Disabled());
   MOZ_ASSERT(clone->Equals(this));
 
   return clone;
 }
 
 void nsHttpConnectionInfo::CloneAsDirectRoute(nsHttpConnectionInfo **outCI) {
   if (mRoutedHost.IsEmpty()) {
     *outCI = Clone();
@@ -260,16 +272,19 @@ void nsHttpConnectionInfo::CloneAsDirect
   clone->SetAnonymous(GetAnonymous());
   clone->SetPrivate(GetPrivate());
   clone->SetInsecureScheme(GetInsecureScheme());
   clone->SetNoSpdy(GetNoSpdy());
   clone->SetBeConservative(GetBeConservative());
   clone->SetTlsFlags(GetTlsFlags());
   clone->SetTrrUsed(GetTrrUsed());
   clone->SetTrrDisabled(GetTrrDisabled());
+  clone->SetIPv4Disabled(GetIPv4Disabled());
+  clone->SetIPv6Disabled(GetIPv6Disabled());
+
   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]
 
   if (!mUsingHttpsProxy) {
@@ -290,16 +305,30 @@ nsresult nsHttpConnectionInfo::CreateWil
 
 void nsHttpConnectionInfo::SetTrrDisabled(bool aNoTrr) {
   if (mTrrDisabled != aNoTrr) {
     mTrrDisabled = aNoTrr;
     BuildHashKey();
   }
 }
 
+void nsHttpConnectionInfo::SetIPv4Disabled(bool aNoIPv4) {
+  if (mIPv4Disabled != aNoIPv4) {
+    mIPv4Disabled = aNoIPv4;
+    BuildHashKey();
+  }
+}
+
+void nsHttpConnectionInfo::SetIPv6Disabled(bool aNoIPv6) {
+  if (mIPv6Disabled != aNoIPv6) {
+    mIPv6Disabled = aNoIPv6;
+    BuildHashKey();
+  }
+}
+
 void nsHttpConnectionInfo::SetTlsFlags(uint32_t aTlsFlags) {
   mTlsFlags = aTlsFlags;
 
   mHashKey.Replace(18, 8, nsPrintfCString("%08x", mTlsFlags));
 }
 
 bool nsHttpConnectionInfo::UsingProxy() {
   if (!mProxyInfo) return false;
--- a/netwerk/protocol/http/nsHttpConnectionInfo.h
+++ b/netwerk/protocol/http/nsHttpConnectionInfo.h
@@ -128,16 +128,22 @@ class nsHttpConnectionInfo final : publi
   void SetTrrUsed(bool aUsed) { mTrrUsed = aUsed; }
   bool GetTrrUsed() const { return mTrrUsed; }
 
   // SetTrrDisabled means don't use TRR to resolve host names for this
   // connection
   void SetTrrDisabled(bool aNoTrr);
   bool GetTrrDisabled() const { return mTrrDisabled; }
 
+  void SetIPv4Disabled(bool aNoIPv4);
+  bool GetIPv4Disabled() const { return mIPv4Disabled; }
+
+  void SetIPv6Disabled(bool aNoIPv6);
+  bool GetIPv6Disabled() const { return mIPv6Disabled; }
+
   const nsCString &GetNPNToken() { return mNPNToken; }
   const nsCString &GetUsername() { return mUsername; }
 
   const OriginAttributes &GetOriginAttributes() { return mOriginAttributes; }
 
   // Returns true for any kind of proxy (http, socks, https, etc..)
   bool UsingProxy();
 
@@ -185,16 +191,18 @@ class nsHttpConnectionInfo final : publi
   bool mEndToEndSSL;
   bool mUsingConnect;  // if will use CONNECT with http proxy
   nsCString mNPNToken;
   OriginAttributes mOriginAttributes;
 
   uint32_t mTlsFlags;
   uint16_t mTrrUsed : 1;
   uint16_t mTrrDisabled : 1;
+  uint16_t mIPv4Disabled : 1;
+  uint16_t mIPv6Disabled : 1;
 
   bool mLessThanTls13;  // This will be set to true if we negotiate less than
                         // tls1.3. If the tls version is till not know or it
                         // is 1.3 or greater the value will be false.
 
   // for RefPtr
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsHttpConnectionInfo, override)
 };
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -3943,17 +3943,21 @@ nsresult nsHttpConnectionMgr::nsHalfOpen
     tmpFlags |= nsISocketTransport::DONT_TRY_ESNI;
   }
 
   if ((mCaps & NS_HTTP_BE_CONSERVATIVE) || ci->GetBeConservative()) {
     LOG(("Setting Socket to BE_CONSERVATIVE"));
     tmpFlags |= nsISocketTransport::BE_CONSERVATIVE;
   }
 
-  if (mEnt->PreferenceKnown()) {
+  if (mCaps & NS_HTTP_DISABLE_IPV4) {
+    tmpFlags |= nsISocketTransport::DISABLE_IPV4;
+  } else if (mCaps & NS_HTTP_DISABLE_IPV6) {
+    tmpFlags |= nsISocketTransport::DISABLE_IPV6;
+  } else if (mEnt->PreferenceKnown()) {
     if (mEnt->mPreferIPv6) {
       tmpFlags |= nsISocketTransport::DISABLE_IPV4;
     } else if (mEnt->mPreferIPv4) {
       tmpFlags |= nsISocketTransport::DISABLE_IPV6;
     }
 
     // In case the host is no longer accessible via the preferred IP family,
     // try the opposite one and potentially restate the preference.
@@ -3983,16 +3987,19 @@ nsresult nsHttpConnectionMgr::nsHalfOpen
   if ((mFastOpenStatus != TFO_HTTP) && !isBackup) {
     if (mEnt->mUseFastOpen) {
       socketTransport->SetFastOpenCallback(this);
     } else {
       mFastOpenStatus = TFO_DISABLED;
     }
   }
 
+  MOZ_ASSERT(!(tmpFlags & nsISocketTransport::DISABLE_IPV4) ||
+                 !(tmpFlags & nsISocketTransport::DISABLE_IPV6),
+             "Both types should not be disabled at the same time.");
   socketTransport->SetConnectionFlags(tmpFlags);
   socketTransport->SetTlsFlags(ci->GetTlsFlags());
 
   const OriginAttributes &originAttributes =
       mEnt->mConnInfo->GetOriginAttributes();
   if (originAttributes != OriginAttributes()) {
     socketTransport->SetOriginAttributes(originAttributes);
   }
--- a/netwerk/protocol/http/nsIHttpChannelInternal.idl
+++ b/netwerk/protocol/http/nsIHttpChannelInternal.idl
@@ -353,9 +353,20 @@ interface nsIHttpChannelInternal : nsISu
     /**
      * Cancel a channel because we have determined that it needs to be blocked
      * for tracking protection.  This is an internal API that is meant to be
      * called by the channel classifier.  Please DO NOT use this API if you don't
      * know whether you should be using it.
      */
     [noscript] void cancelForTrackingProtection();
 
+    /**
+     * The channel will be loaded over IPv6, disabling IPv4.
+     */
+    [noscript, notxpcom, nostdcall]
+    void setIPv4Disabled();
+
+    /**
+     * The channel will be loaded over IPv4, disabling IPv6.
+     */
+    [noscript, notxpcom, nostdcall]
+    void setIPv6Disabled();
 };
--- a/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
+++ b/netwerk/protocol/viewsource/nsViewSourceChannel.cpp
@@ -1047,8 +1047,20 @@ nsViewSourceChannel::LogBlockedCORSReque
 
 const nsTArray<mozilla::Tuple<nsCString, nsCString>>
     &nsViewSourceChannel::PreferredAlternativeDataTypes() {
   if (mCacheInfoChannel) {
     return mCacheInfoChannel->PreferredAlternativeDataTypes();
   }
   return mEmptyArray;
 }
+
+void nsViewSourceChannel::SetIPv4Disabled() {
+  if (mHttpChannelInternal) {
+    mHttpChannelInternal->SetIPv4Disabled();
+  }
+}
+
+void nsViewSourceChannel::SetIPv6Disabled() {
+  if (mHttpChannelInternal) {
+    mHttpChannelInternal->SetIPv6Disabled();
+  }
+}