Bug 1334443 - Add gtest for nsProtocolProxyService::{LoadHostFilters,CanUseProxy} and fix IPv6 parsing r=bagder draft
authorValentin Gosu <valentin.gosu@gmail.com>
Mon, 20 Mar 2017 20:20:42 +0100
changeset 501643 757a19a50a50b2af232f0b44f6faacf7280b554a
parent 501522 8d967436d696d1f8e3fb33cf7e3d32a72457ffa6
child 501644 9fac33114b16d0910e63b474222acf0bc1db500f
push id50068
push uservalentin.gosu@gmail.com
push dateMon, 20 Mar 2017 19:21:53 +0000
reviewersbagder
bugs1334443
milestone55.0a1
Bug 1334443 - Add gtest for nsProtocolProxyService::{LoadHostFilters,CanUseProxy} and fix IPv6 parsing r=bagder While writing a gtest I discovered the parsing an IPv6 address didn't work due to the brackets. MozReview-Commit-ID: 9mmKS72hf7Y
netwerk/base/nsProtocolProxyService.cpp
netwerk/base/nsProtocolProxyService.h
netwerk/test/gtest/TestProtocolProxyService.cpp
netwerk/test/gtest/moz.build
--- a/netwerk/base/nsProtocolProxyService.cpp
+++ b/netwerk/base/nsProtocolProxyService.cpp
@@ -1524,18 +1524,24 @@ nsProtocolProxyService::LoadHostFilters(
             // Continue to next host filter;
             continue;
         }
 
         // For all other host filters, create HostInfo object and add to list
         HostInfo *hinfo = new HostInfo();
         hinfo->port = portLocation ? atoi(portLocation + 1) : 0;
 
+        // PR_StringToNetAddr can't parse brackets enclosed IPv6
+        nsAutoCString addrString = str;
+        if (str.Length() > 0 && str.First() == '[' && str.Last() == ']') {
+            addrString = Substring(str, 1, str.Length() - 2);
+        }
+
         PRNetAddr addr;
-        if (PR_StringToNetAddr(str.get(), &addr) == PR_SUCCESS) {
+        if (PR_StringToNetAddr(addrString.get(), &addr) == PR_SUCCESS) {
             hinfo->is_ipaddr   = true;
             hinfo->ip.family   = PR_AF_INET6; // we always store address as IPv6
             hinfo->ip.mask_len = maskLocation ? atoi(maskLocation + 1) : 128;
 
             if (hinfo->ip.mask_len == 0) {
                 NS_WARNING("invalid mask");
                 goto loser;
             }
@@ -1573,17 +1579,17 @@ nsProtocolProxyService::LoadHostFilters(
             if (!hinfo->name.host)
                 goto loser;
 
             hinfo->name.host_len = endIndex - startIndex;
         }
 
 //#define DEBUG_DUMP_FILTERS
 #ifdef DEBUG_DUMP_FILTERS
-        printf("loaded filter[%u]:\n", mHostFiltersArray.Length());
+        printf("loaded filter[%zu]:\n", mHostFiltersArray.Length());
         printf("  is_ipaddr = %u\n", hinfo->is_ipaddr);
         printf("  port = %u\n", hinfo->port);
         if (hinfo->is_ipaddr) {
             printf("  ip.family = %x\n", hinfo->ip.family);
             printf("  ip.mask_len = %u\n", hinfo->ip.mask_len);
 
             PRNetAddr netAddr;
             PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, 0, &netAddr);
--- a/netwerk/base/nsProtocolProxyService.h
+++ b/netwerk/base/nsProtocolProxyService.h
@@ -49,16 +49,17 @@ public:
     NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROTOCOL_PROXY_SERVICE_IMPL_CID)
 
     nsProtocolProxyService();
 
     nsresult Init();
 
 protected:
     friend class nsAsyncResolveRequest;
+    friend class TestProtocolProxyService_LoadHostFilters_Test; // for gtest
 
     ~nsProtocolProxyService();
 
     /**
      * This method is called whenever a preference may have changed or
      * to initialize all preferences.
      *
      * @param prefs
new file mode 100644
--- /dev/null
+++ b/netwerk/test/gtest/TestProtocolProxyService.cpp
@@ -0,0 +1,123 @@
+#include "gtest/gtest.h"
+
+#include "nsCOMPtr.h"
+#include "nsNetCID.h"
+#include "nsIURL.h"
+#include "nsString.h"
+#include "nsComponentManagerUtils.h"
+#include "../../base/nsProtocolProxyService.h"
+#include "nsServiceManagerUtils.h"
+#include "mozilla/Preferences.h"
+
+namespace mozilla {
+namespace net {
+
+TEST(TestProtocolProxyService, LoadHostFilters) {
+  nsCOMPtr<nsIProtocolProxyService2> ps = do_GetService(NS_PROTOCOLPROXYSERVICE_CID);
+  ASSERT_TRUE(ps);
+  mozilla::net::nsProtocolProxyService* pps = static_cast<mozilla::net::nsProtocolProxyService*>(ps.get());
+
+  nsCOMPtr<nsIURL> url( do_CreateInstance(NS_STANDARDURL_CONTRACTID) );
+  ASSERT_TRUE(url) << "couldn't create URL";
+
+  nsAutoCString spec;
+
+  auto CheckLoopbackURLs = [&](bool expected)
+  {
+    // loopback IPs are always filtered
+    spec = "http://127.0.0.1";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+    spec = "http://[::1]";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+  };
+
+  auto CheckURLs = [&](bool expected)
+  {
+    spec = "http://example.com";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "https://10.2.3.4";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 443), expected);
+
+    spec = "http://1.2.3.4";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "http://1.2.3.4:8080";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "http://[2001::1]";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "http://2.3.4.5:7777";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "http://[abcd::2]:123";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+
+    spec = "http://bla.test.com";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+  };
+
+  auto CheckPortDomain = [&](bool expected)
+  {
+    spec = "http://blabla.com:10";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+  };
+
+  auto CheckLocalDomain = [&](bool expected)
+  {
+    spec = "http://test";
+    ASSERT_EQ(url->SetSpec(spec), NS_OK);
+    ASSERT_EQ(pps->CanUseProxy(url, 80), expected);
+  };
+
+  // --------------------------------------------------------------------------
+
+  nsAutoCString filter;
+
+  // Anything is allowed when there are no filters set
+  printf("Testing empty filter: %s\n", filter.get());
+  pps->LoadHostFilters(filter.get());
+
+  CheckLoopbackURLs(true); // only time when loopbacks can be proxied. bug?
+  CheckLocalDomain(true);
+  CheckURLs(true);
+  CheckPortDomain(true);
+
+  // --------------------------------------------------------------------------
+
+  filter = "example.com, 1.2.3.4/16, [2001::1], 10.0.0.0/8, 2.3.0.0/16:7777, [abcd::1]/64:123, *.test.com";
+  printf("Testing filter: %s\n", filter.get());
+  pps->LoadHostFilters(filter.get());
+  // Check URLs can no longer use filtered proxy
+  CheckURLs(false);
+  CheckLoopbackURLs(false);
+  CheckLocalDomain(true);
+  CheckPortDomain(true);
+
+  // --------------------------------------------------------------------------
+
+  // This is space separated. See bug 1346711 comment 4. We check this to keep
+  // backwards compatibility.
+  filter = "<local> blabla.com:10";
+  printf("Testing filter: %s\n", filter.get());
+  pps->LoadHostFilters(filter.get());
+  CheckURLs(true);
+  CheckLoopbackURLs(false);
+  CheckLocalDomain(false);
+  CheckPortDomain(false);
+}
+
+} // namespace net
+} // namespace mozila
--- a/netwerk/test/gtest/moz.build
+++ b/netwerk/test/gtest/moz.build
@@ -1,13 +1,14 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 UNIFIED_SOURCES += [
+    'TestProtocolProxyService.cpp',
     'TestStandardURL.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul-gtest'