Bug 1215723 - Part 3: Propagate updates to DataStorage from the parent process to the content processes; r=keeler
authorEhsan Akhgari <ehsan@mozilla.com>
Fri, 30 Oct 2015 15:30:00 -0400
changeset 308298 81a5f140ea34afa1417f6c19324c1ede06cbdea5
parent 308297 671540abe891b29d758ed75f6bfae1f0f7fca1e6
child 308299 b35d2c16759cd1231c6ddac4900ed9da6a72095a
push id7450
push userahalberstadt@mozilla.com
push dateWed, 11 Nov 2015 20:09:05 +0000
reviewerskeeler
bugs1215723
milestone45.0a1
Bug 1215723 - Part 3: Propagate updates to DataStorage from the parent process to the content processes; r=keeler
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/PContent.ipdl
security/manager/ssl/DataStorage.cpp
security/manager/ssl/DataStorage.h
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2258,16 +2258,49 @@ ContentChild::RecvSystemMemoryAvailable(
 bool
 ContentChild::RecvPreferenceUpdate(const PrefSetting& aPref)
 {
     Preferences::SetPreference(aPref);
     return true;
 }
 
 bool
+ContentChild::RecvDataStoragePut(const nsString& aFilename,
+                                 const DataStorageItem& aItem)
+{
+    RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+    if (storage) {
+        storage->Put(aItem.key(), aItem.value(), aItem.type());
+    }
+    return true;
+}
+
+bool
+ContentChild::RecvDataStorageRemove(const nsString& aFilename,
+                                    const nsCString& aKey,
+                                    const DataStorageType& aType)
+{
+    RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+    if (storage) {
+        storage->Remove(aKey, aType);
+    }
+    return true;
+}
+
+bool
+ContentChild::RecvDataStorageClear(const nsString& aFilename)
+{
+    RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename);
+    if (storage) {
+        storage->Clear();
+    }
+    return true;
+}
+
+bool
 ContentChild::RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData)
 {
     for (uint32_t i = 0; i < mAlertObservers.Length();
          /*we mutate the array during the loop; ++i iff no mutation*/) {
         AlertObserver* observer = mAlertObservers[i];
         if (observer->Observes(aData) && observer->Notify(aType)) {
             // if aType == alertfinished, this alert is done.  we can
             // remove the observer.
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -333,16 +333,23 @@ public:
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvSystemMemoryAvailable(const uint64_t& aGetterId,
                                            const uint32_t& aMemoryAvailable) override;
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref) override;
 
+    virtual bool RecvDataStoragePut(const nsString& aFilename,
+                                    const DataStorageItem& aItem) override;
+    virtual bool RecvDataStorageRemove(const nsString& aFilename,
+                                       const nsCString& aKey,
+                                       const DataStorageType& aType) override;
+    virtual bool RecvDataStorageClear(const nsString& aFilename) override;
+
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType,
                                           const nsString& aData) override;
 
     virtual bool RecvLoadProcessScript(const nsString& aURL) override;
 
     virtual bool RecvAsyncMessage(const nsString& aMsg,
                                   const ClonedMessageData& aData,
                                   InfallibleTArray<CpowEntry>&& aCpows,
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -561,16 +561,20 @@ child:
     async SetConnectivity(bool connectivity);
 
     async NotifyVisited(URIParams uri);
 
     async SystemMemoryAvailable(uint64_t getterId, uint32_t memoryAvailable);
 
     PreferenceUpdate(PrefSetting pref);
 
+    DataStoragePut(nsString aFilename, DataStorageItem aItem);
+    DataStorageRemove(nsString aFilename, nsCString aKey, DataStorageType aType);
+    DataStorageClear(nsString aFilename);
+
     NotifyAlertsObserver(nsCString topic, nsString data);
 
     GeolocationUpdate(GeoPosition somewhere);
 
     GeolocationError(uint16_t errorCode);
 
     UpdateDictionaryList(nsString[] dictionaries);
 
--- a/security/manager/ssl/DataStorage.cpp
+++ b/security/manager/ssl/DataStorage.cpp
@@ -4,16 +4,17 @@
  * 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 "DataStorage.h"
 
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/dom/PContent.h"
 #include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Services.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/unused.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsIObserverService.h"
 #include "nsITimer.h"
@@ -67,16 +68,29 @@ DataStorage::Get(const nsString& aFilena
   RefPtr<DataStorage> storage;
   if (!sDataStorages->Get(aFilename, getter_AddRefs(storage))) {
     storage = new DataStorage(aFilename);
     sDataStorages->Put(aFilename, storage);
   }
   return storage.forget();
 }
 
+// static
+already_AddRefed<DataStorage>
+DataStorage::GetIfExists(const nsString& aFilename)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!sDataStorages) {
+    sDataStorages = new DataStorages();
+  }
+  RefPtr<DataStorage> storage;
+  sDataStorages->Get(aFilename, getter_AddRefs(storage));
+  return storage.forget();
+}
+
 nsresult
 DataStorage::Init(bool& aDataWillPersist)
 {
   // Don't access the observer service or preferences off the main thread.
   if (!NS_IsMainThread()) {
     NS_NOTREACHED("DataStorage::Init called off main thread");
     return NS_ERROR_NOT_SAME_THREAD;
   }
@@ -515,16 +529,32 @@ DataStorage::MaybeEvictOneEntry(DataStor
         toEvict.mEntry = entry;
       }
     }
 
     table.Remove(toEvict.mKey);
   }
 }
 
+template <class Functor>
+static
+void
+RunOnAllContentParents(Functor func)
+{
+  if (!XRE_IsParentProcess()) {
+    return;
+  }
+  using dom::ContentParent;
+  nsTArray<ContentParent*> parents;
+  ContentParent::GetAll(parents);
+  for (auto& parent: parents) {
+    func(parent);
+  }
+}
+
 nsresult
 DataStorage::Put(const nsCString& aKey, const nsCString& aValue,
                  DataStorageType aType)
 {
   WaitForReady();
   MutexAutoLock lock(mMutex);
 
   nsresult rv;
@@ -541,16 +571,24 @@ DataStorage::Put(const nsCString& aKey, 
     MaybeEvictOneEntry(aType, lock);
   }
   entry.mValue = aValue;
   rv = PutInternal(aKey, entry, aType, lock);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
+  RunOnAllContentParents([&](dom::ContentParent* aParent) {
+    DataStorageItem item;
+    item.key() = aKey;
+    item.value() = aValue;
+    item.type() = aType;
+    Unused << aParent->SendDataStoragePut(mFilename, item);
+  });
+
   return NS_OK;
 }
 
 nsresult
 DataStorage::PutInternal(const nsCString& aKey, Entry& aEntry,
                          DataStorageType aType,
                          const MutexAutoLock& aProofOfLock)
 {
@@ -571,16 +609,20 @@ DataStorage::Remove(const nsCString& aKe
   MutexAutoLock lock(mMutex);
 
   DataStorageTable& table = GetTableForType(aType, lock);
   table.Remove(aKey);
 
   if (aType == DataStorage_Persistent && !mPendingWrite) {
     Unused << AsyncSetTimer(lock);
   }
+
+  RunOnAllContentParents([&](dom::ContentParent* aParent) {
+    Unused << aParent->SendDataStorageRemove(mFilename, aKey, aType);
+  });
 }
 
 class DataStorage::Writer : public nsRunnable
 {
 public:
   Writer(nsCString& aData, DataStorage* aDataStorage)
     : mData(aData)
     , mDataStorage(aDataStorage)
@@ -691,16 +733,21 @@ DataStorage::Clear()
     // Asynchronously clear the file. This is similar to the permission manager
     // in that it doesn't wait to synchronously remove the data from its backing
     // storage either.
     nsresult rv = AsyncWriteData(lock);
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
+
+  RunOnAllContentParents([&](dom::ContentParent* aParent) {
+    Unused << aParent->SendDataStorageClear(mFilename);
+  });
+
   return NS_OK;
 }
 
 /* static */
 void
 DataStorage::TimerCallback(nsITimer* aTimer, void* aClosure)
 {
   MOZ_ASSERT(XRE_IsParentProcess());
--- a/security/manager/ssl/DataStorage.h
+++ b/security/manager/ssl/DataStorage.h
@@ -91,16 +91,17 @@ class DataStorage : public nsIObserver
 
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   // If there is a profile directory, there is or will eventually be a file
   // by the name specified by aFilename there.
   static already_AddRefed<DataStorage> Get(const nsString& aFilename);
+  static already_AddRefed<DataStorage> GetIfExists(const nsString& aFilename);
 
   // Initializes the DataStorage. Must be called before using.
   // aDataWillPersist returns whether or not data can be persistently saved.
   nsresult Init(/*out*/bool& aDataWillPersist);
   // Given a key and a type of data, returns a value. Returns an empty string if
   // the key is not present for that type of data. If Get is called before the
   // "data-storage-ready" event is observed, it will block. NB: It is not
   // currently possible to differentiate between missing data and data that is