Bug 1563246 - Reload the Public Suffix List when data is updated in profile folder r=leplatrem,kmag
authorArpit Bharti <arpitbharti73@gmail.com>
Fri, 23 Aug 2019 10:56:59 +0000
changeset 489846 03c9cce08d1126e337938b919852704cb3469358
parent 489845 d9b024555ac15ecc7f9e9e6e01f92a752deb9040
child 489847 e1a536d26d80db9fe9960e1d0c10bddc583f64f1
push id36491
push usermalexandru@mozilla.com
push dateMon, 26 Aug 2019 22:30:36 +0000
treeherdermozilla-central@5c7635de0cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersleplatrem, kmag
bugs1563246
milestone70.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 1563246 - Reload the Public Suffix List when data is updated in profile folder r=leplatrem,kmag Differential Revision: https://phabricator.services.mozilla.com/D42470
netwerk/dns/nsEffectiveTLDService.cpp
netwerk/dns/nsEffectiveTLDService.h
netwerk/dns/tests/unit/test_nsEffectiveTLDService_Reload_DAFSA.js
netwerk/dns/tests/unit/xpcshell.ini
--- a/netwerk/dns/nsEffectiveTLDService.cpp
+++ b/netwerk/dns/nsEffectiveTLDService.cpp
@@ -5,62 +5,103 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // This service reads a file of rules describing TLD-like domain names.  For a
 // complete description of the expected file format and parsing rules, see
 // http://wiki.mozilla.org/Gecko:Effective_TLD_Service
 
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/HashFunctions.h"
-#include "mozilla/Maybe.h"
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/ResultExtensions.h"
 
 #include "MainThreadUtils.h"
+#include "nsCRT.h"
 #include "nsEffectiveTLDService.h"
+#include "nsIFile.h"
 #include "nsIIDNService.h"
-#include "nsNetUtil.h"
-#include "prnetdb.h"
+#include "nsIObserverService.h"
 #include "nsIURI.h"
 #include "nsNetCID.h"
+#include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
+#include "prnetdb.h"
 
 namespace etld_dafsa {
 
 // Generated file that includes kDafsa
 #include "etld_data.inc"
 
 }  // namespace etld_dafsa
 
 using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(nsEffectiveTLDService, nsIEffectiveTLDService,
-                  nsIMemoryReporter)
+                  nsIMemoryReporter, nsIObserver)
 
 // ----------------------------------------------------------------------
 
 static nsEffectiveTLDService* gService = nullptr;
 
 nsEffectiveTLDService::nsEffectiveTLDService()
-    : mIDNService(), mGraph(etld_dafsa::kDafsa) {}
+    : mIDNService(), mGraphLock("nsEffectiveTLDService::mGraph") {
+  mGraph.emplace(etld_dafsa::kDafsa);
+}
 
 nsresult nsEffectiveTLDService::Init() {
+  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+  obs->AddObserver(this, "public-suffix-list-updated", false);
+
   if (gService) {
     return NS_ERROR_ALREADY_INITIALIZED;
   }
 
   nsresult rv;
   mIDNService = do_GetService(NS_IDNSERVICE_CONTRACTID, &rv);
   if (NS_FAILED(rv)) return rv;
 
   gService = this;
   RegisterWeakMemoryReporter(this);
 
   return NS_OK;
 }
 
+NS_IMETHODIMP nsEffectiveTLDService::Observe(nsISupports* aSubject,
+                                             const char* aTopic,
+                                             const char16_t* aData) {
+  /**
+   * Signal sent from netwerk/dns/PublicSuffixList.jsm
+   * aSubject is the nsIFile object for dafsa.bin
+   * aData is the absolute path to the dafsa.bin file (not used)
+   */
+  if (aSubject && (nsCRT::strcmp(aTopic, "public-suffix-list-updated") == 0)) {
+    nsCOMPtr<nsIFile> mDafsaBinFile(do_QueryInterface(aSubject));
+    NS_ENSURE_TRUE(mDafsaBinFile, NS_ERROR_ILLEGAL_VALUE);
+
+    AutoWriteLock lock(mGraphLock);
+    // Reset mGraph with kDafsa in case reassigning to mDafsaMap fails
+    mGraph.reset();
+    mGraph.emplace(etld_dafsa::kDafsa);
+
+    mDafsaMap.reset();
+    mMruTable.Clear();
+
+    MOZ_TRY(mDafsaMap.init(mDafsaBinFile));
+
+    size_t size = mDafsaMap.size();
+    const uint8_t* remoteDafsaPtr = mDafsaMap.get<uint8_t>().get();
+
+    auto remoteDafsa = mozilla::MakeSpan(remoteDafsaPtr, size);
+
+    mGraph.reset();
+    mGraph.emplace(remoteDafsa);
+  }
+  return NS_OK;
+}
+
 nsEffectiveTLDService::~nsEffectiveTLDService() {
   UnregisterWeakMemoryReporter(this);
   if (mIDNService) {
     // Only clear gService if Init() finished successfully.
     gService = nullptr;
   }
 }
 
@@ -249,31 +290,35 @@ nsresult nsEffectiveTLDService::GetBaseD
   // have multiple attributes (e.g. IsWild() and IsNormal()).
   const char* prevDomain = nullptr;
   const char* currDomain = aHostname.get();
   const char* nextDot = strchr(currDomain, '.');
   const char* end = currDomain + aHostname.Length();
   // Default value of *eTLD is currDomain as set in the while loop below
   const char* eTLD = nullptr;
   while (true) {
-    // sanity check the string we're about to look up: it should not begin with
-    // a '.'; this would mean the hostname began with a '.' or had an
+    // sanity check the string we're about to look up: it should not begin
+    // with a '.'; this would mean the hostname began with a '.' or had an
     // embedded '..' sequence.
     if (*currDomain == '.') {
       // Update the MRU table if in use.
       if (entry) {
         entry->Set(
             TLDCacheEntry{aHostname, EmptyCString(), NS_ERROR_INVALID_ARG});
       }
 
       return NS_ERROR_INVALID_ARG;
     }
 
-    // Perform the lookup.
-    const int result = mGraph.Lookup(Substring(currDomain, end));
+    int result;
+    {
+      AutoReadLock lock(mGraphLock);
+      // Perform the lookup.
+      result = mGraph->Lookup(Substring(currDomain, end));
+    }
     if (result != Dafsa::kKeyNotFound) {
       if (result == kWildcardRule && prevDomain) {
         // wildcard rules imply an eTLD one level inferior to the match.
         eTLD = prevDomain;
         break;
       }
       if ((result == kWildcardRule || result != kExceptionRule) || !nextDot) {
         // specific match, or we've hit the top domain level
@@ -281,16 +326,17 @@ nsresult nsEffectiveTLDService::GetBaseD
         break;
       }
       if (result == kExceptionRule) {
         // exception rules imply an eTLD one level superior to the match.
         eTLD = nextDot + 1;
         break;
       }
     }
+
     if (!nextDot) {
       // we've hit the top domain level; use it by default.
       eTLD = currDomain;
       break;
     }
 
     prevDomain = currDomain;
     currDomain = nextDot + 1;
--- a/netwerk/dns/nsEffectiveTLDService.h
+++ b/netwerk/dns/nsEffectiveTLDService.h
@@ -3,33 +3,40 @@
  * 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/. */
 
 #ifndef EffectiveTLDService_h
 #define EffectiveTLDService_h
 
 #include "nsIEffectiveTLDService.h"
 
+#include "mozilla/AutoMemMap.h"
+#include "mozilla/Attributes.h"
+#include "mozilla/Dafsa.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/MemoryReporting.h"
+#include "mozilla/MruCache.h"
+#include "mozilla/RWLock.h"
+
+#include "nsCOMPtr.h"
 #include "nsHashKeys.h"
 #include "nsIMemoryReporter.h"
+#include "nsIObserver.h"
 #include "nsString.h"
-#include "nsCOMPtr.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/Dafsa.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/MruCache.h"
 
 class nsIIDNService;
 
 class nsEffectiveTLDService final : public nsIEffectiveTLDService,
+                                    public nsIObserver,
                                     public nsIMemoryReporter {
  public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIEFFECTIVETLDSERVICE
   NS_DECL_NSIMEMORYREPORTER
+  NS_DECL_NSIOBSERVER
 
   nsEffectiveTLDService();
   nsresult Init();
 
   static nsEffectiveTLDService* GetInstance();
 
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
@@ -37,17 +44,23 @@ class nsEffectiveTLDService final : publ
   nsresult GetBaseDomainInternal(nsCString& aHostname, int32_t aAdditionalParts,
                                  nsACString& aBaseDomain);
   nsresult NormalizeHostname(nsCString& aHostname);
   ~nsEffectiveTLDService();
 
   nsCOMPtr<nsIIDNService> mIDNService;
 
   // The DAFSA provides a compact encoding of the rather large eTLD list.
-  mozilla::Dafsa mGraph;
+  mozilla::Maybe<mozilla::Dafsa> mGraph;
+
+  // Memory map used for a new updated dafsa
+  mozilla::loader::AutoMemMap mDafsaMap;
+
+  // Lock for mGraph and mDafsaMap
+  mozilla::RWLock mGraphLock;
 
   // Note that the cache entries here can record entries that were cached
   // successfully or unsuccessfully.  mResult must be checked before using an
   // entry.  If it's a success error code, the cache entry is valid and can be
   // used.
   struct TLDCacheEntry {
     nsCString mHost;
     nsCString mBaseDomain;
new file mode 100644
--- /dev/null
+++ b/netwerk/dns/tests/unit/test_nsEffectiveTLDService_Reload_DAFSA.js
@@ -0,0 +1,31 @@
+"use strict";
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const SIGNAL = "public-suffix-list-updated";
+
+add_task(async () => {
+  info("Before fake dafsa reload.");
+
+  let suffix = Services.eTLD.getPublicSuffixFromHost("website.xpcshelltest");
+  Assert.equal(
+    suffix,
+    "xpcshelltest",
+    "Fake Suffix does not exist in current PSL."
+  );
+});
+
+add_task(async () => {
+  info("After fake dafsa reload.");
+
+  // reload the PSL with fake data containing .xpcshelltest
+  const fakeDafsaFile = do_get_file("data/fake_remote_dafsa.bin");
+  Services.obs.notifyObservers(fakeDafsaFile, SIGNAL, fakeDafsaFile.path);
+
+  let suffix = Services.eTLD.getPublicSuffixFromHost("website.xpcshelltest");
+  Assert.equal(
+    suffix,
+    "website.xpcshelltest",
+    "Fake Suffix now exists in PSL after DAFSA reload."
+  );
+});
--- a/netwerk/dns/tests/unit/xpcshell.ini
+++ b/netwerk/dns/tests/unit/xpcshell.ini
@@ -1,6 +1,7 @@
 [DEFAULT]
 head = ../../../../services/common/tests/unit/head_global.js ../../../../services/common/tests/unit/head_helpers.js
 firefox-appdir = browser
 support-files = data/**
 
 [test_PublicSuffixList.js]
+[test_nsEffectiveTLDService_Reload_DAFSA.js]