Bug 1258977 - Part 3: handle special case to follow the test; r=bagder
authorLiang-Heng Chen <xeonchen@mozilla.com>
Thu, 26 May 2016 17:48:51 +0800
changeset 338849 285bc19d2b16254420f595ed9e5de606a57fdc68
parent 338848 fd981e994ec94e20bcf4251b7920bc36f9ca697e
child 338850 15ba5d12b73b122aaad76aeeac2f7648d442a31f
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbagder
bugs1258977
milestone49.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 1258977 - Part 3: handle special case to follow the test; r=bagder MozReview-Commit-ID: ImGSoBMwQvx
toolkit/system/osxproxy/ProxyUtils.mm
toolkit/system/windowsproxy/ProxyUtils.cpp
--- a/toolkit/system/osxproxy/ProxyUtils.mm
+++ b/toolkit/system/osxproxy/ProxyUtils.mm
@@ -44,18 +44,19 @@ MaskIPv4Addr(PRUint32 aAddr, uint16_t aM
     return aAddr;
   }
   return PR_htonl(PR_ntohl(aAddr) & (~0L << (32 - aMaskLen)));
 }
 
 static void
 MaskIPv6Addr(PRIPv6Addr& aAddr, uint16_t aMaskLen)
 {
-  if (aMaskLen == 128)
+  if (aMaskLen == 128) {
     return;
+  }
 
   if (aMaskLen > 96) {
     aAddr.pr_s6_addr32[3] = PR_htonl(
         PR_ntohl(aAddr.pr_s6_addr32[3]) & (~0L << (128 - aMaskLen)));
   } else if (aMaskLen > 64) {
     aAddr.pr_s6_addr32[3] = 0;
     aAddr.pr_s6_addr32[2] = PR_htonl(
         PR_ntohl(aAddr.pr_s6_addr32[2]) & (~0L << (96 - aMaskLen)));
@@ -139,25 +140,33 @@ IsMatchWildcard(const nsACString& aHost,
   while (tokenStart < overrideLength) {
     int32_t tokenEnd = override.FindChar('*', tokenStart);
     if (tokenEnd == tokenStart) {
       // Star is the first character in the token.
       star = true;
       tokenStart++;
       // If the character following the '*' is a '.' character then skip
       // it so that "*.foo.com" allows "foo.com".
-      if (override.FindChar('.', tokenStart) == tokenStart)
-        tokenStart++;
+      if (override.FindChar('.', tokenStart) == tokenStart) {
+        nsAutoCString token(Substring(override,
+                                      tokenStart + 1,
+                                      overrideLength - tokenStart - 1));
+        if (host.Equals(token)) {
+          return true;
+        }
+      }
     } else {
-      if (tokenEnd == -1)
+      if (tokenEnd == -1) {
         tokenEnd = overrideLength; // no '*' char, match rest of string
+      }
       nsAutoCString token(Substring(override, tokenStart, tokenEnd - tokenStart));
       offset = host.Find(token, offset);
-      if (offset == -1 || (!star && offset))
+      if (offset == -1 || (!star && offset)) {
         return false;
+      }
       star = false;
       tokenStart = tokenEnd;
       offset += token.Length();
     }
   }
 
   return (star || (offset == static_cast<int32_t>(host.Length())));
 }
--- a/toolkit/system/windowsproxy/ProxyUtils.cpp
+++ b/toolkit/system/windowsproxy/ProxyUtils.cpp
@@ -1,52 +1,182 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ProxyUtils.h"
+#include "nsTArray.h"
+#include "prnetdb.h"
+#include "prtypes.h"
 
 namespace mozilla {
 namespace toolkit {
 namespace system {
 
-bool IsHostProxyEntry(const nsACString& aHost, const nsACString& aOverride)
+/**
+ * Normalize the short IP form into the complete form.
+ * For example, it converts "192.168" into "192.168.0.0"
+ */
+static bool
+NormalizeAddr(const nsACString& aAddr, nsCString& aNormalized)
+{
+  nsTArray<nsCString> addr;
+  if (!ParseString(aAddr, '.', addr)) {
+    return false;
+  }
+  aNormalized = "";
+  for (uint32_t i = 0; i < 4; ++i) {
+    if (i != 0) {
+      aNormalized.Append(".");
+    }
+    if (i < addr.Length()) {
+      aNormalized.Append(addr[i]);
+    } else {
+      aNormalized.Append("0");
+    }
+  }
+  return true;
+}
+
+static PRUint32
+MaskIPv4Addr(PRUint32 aAddr, uint16_t aMaskLen)
+{
+  if (aMaskLen == 32) {
+    return aAddr;
+  }
+  return PR_htonl(PR_ntohl(aAddr) & (~0L << (32 - aMaskLen)));
+}
+
+static void
+MaskIPv6Addr(PRIPv6Addr& aAddr, uint16_t aMaskLen)
+{
+  if (aMaskLen == 128) {
+    return;
+  }
+
+  if (aMaskLen > 96) {
+    aAddr.pr_s6_addr32[3] = PR_htonl(
+        PR_ntohl(aAddr.pr_s6_addr32[3]) & (~0L << (128 - aMaskLen)));
+  } else if (aMaskLen > 64) {
+    aAddr.pr_s6_addr32[3] = 0;
+    aAddr.pr_s6_addr32[2] = PR_htonl(
+        PR_ntohl(aAddr.pr_s6_addr32[2]) & (~0L << (96 - aMaskLen)));
+  } else if (aMaskLen > 32) {
+    aAddr.pr_s6_addr32[3] = 0;
+    aAddr.pr_s6_addr32[2] = 0;
+    aAddr.pr_s6_addr32[1] = PR_htonl(
+        PR_ntohl(aAddr.pr_s6_addr32[1]) & (~0L << (64 - aMaskLen)));
+  } else {
+    aAddr.pr_s6_addr32[3] = 0;
+    aAddr.pr_s6_addr32[2] = 0;
+    aAddr.pr_s6_addr32[1] = 0;
+    aAddr.pr_s6_addr32[0] = PR_htonl(
+        PR_ntohl(aAddr.pr_s6_addr32[0]) & (~0L << (32 - aMaskLen)));
+  }
+
+  return;
+}
+
+static bool
+IsMatchMask(const nsACString& aHost, const nsACString& aOverride)
+{
+  nsresult rv;
+
+  auto tokenEnd = aOverride.FindChar('/');
+  if (tokenEnd == -1) {
+    return false;
+  }
+
+  nsAutoCString prefixStr(Substring(aOverride,
+                                    tokenEnd + 1,
+                                    aOverride.Length() - tokenEnd - 1));
+  auto maskLen = prefixStr.ToInteger(&rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return false;
+  }
+
+  nsAutoCString override(aOverride);
+  if (!NormalizeAddr(Substring(aOverride, 0, tokenEnd), override)) {
+    return false;
+  }
+
+  PRNetAddr prAddrHost;
+  PRNetAddr prAddrOverride;
+  if (PR_SUCCESS != PR_StringToNetAddr(PromiseFlatCString(aHost).get(),
+                                       &prAddrHost) ||
+      PR_SUCCESS != PR_StringToNetAddr(override.get(),
+                                       &prAddrOverride)) {
+    return false;
+  }
+
+  if (prAddrHost.raw.family == PR_AF_INET &&
+      prAddrOverride.raw.family == PR_AF_INET) {
+    return MaskIPv4Addr(prAddrHost.inet.ip, maskLen) ==
+           MaskIPv4Addr(prAddrOverride.inet.ip, maskLen);
+  }
+  else if (prAddrHost.raw.family == PR_AF_INET6 &&
+      prAddrOverride.raw.family == PR_AF_INET6) {
+    MaskIPv6Addr(prAddrHost.ipv6.ip, maskLen);
+    MaskIPv6Addr(prAddrOverride.ipv6.ip, maskLen);
+
+    return memcmp(&prAddrHost.ipv6.ip,
+                  &prAddrOverride.ipv6.ip,
+                  sizeof(PRIPv6Addr)) == 0;
+  }
+
+  return false;
+}
+
+static bool
+IsMatchWildcard(const nsACString& aHost, const nsACString& aOverride)
 {
   nsAutoCString host(aHost);
   nsAutoCString override(aOverride);
+
   int32_t overrideLength = override.Length();
   int32_t tokenStart = 0;
   int32_t offset = 0;
   bool star = false;
 
   while (tokenStart < overrideLength) {
     int32_t tokenEnd = override.FindChar('*', tokenStart);
     if (tokenEnd == tokenStart) {
+      // Star is the first character in the token.
       star = true;
       tokenStart++;
       // If the character following the '*' is a '.' character then skip
       // it so that "*.foo.com" allows "foo.com".
       if (override.FindChar('.', tokenStart) == tokenStart) {
-        tokenStart++;
+        nsAutoCString token(Substring(override,
+                                      tokenStart + 1,
+                                      overrideLength - tokenStart - 1));
+        if (host.Equals(token)) {
+          return true;
+        }
       }
     } else {
       if (tokenEnd == -1) {
-        tokenEnd = overrideLength;
+        tokenEnd = overrideLength; // no '*' char, match rest of string
       }
-      nsAutoCString token(Substring(override, tokenStart,
-                                    tokenEnd - tokenStart));
+      nsAutoCString token(Substring(override, tokenStart, tokenEnd - tokenStart));
       offset = host.Find(token, offset);
       if (offset == -1 || (!star && offset)) {
         return false;
       }
       star = false;
       tokenStart = tokenEnd;
       offset += token.Length();
     }
   }
 
-  return (star || (offset == host.Length()));
+  return (star || (offset == static_cast<int32_t>(host.Length())));
+}
+
+bool
+IsHostProxyEntry(const nsACString& aHost, const nsACString& aOverride)
+{
+  return IsMatchMask(aHost, aOverride) || IsMatchWildcard(aHost, aOverride);
 }
 
 } // namespace system
 } // namespace toolkit
 } // namespace mozilla