summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--gnu/local.mk2
-rw-r--r--gnu/packages/gnuzilla.scm19
-rw-r--r--gnu/packages/patches/icecat-bug-1348660-pt5.patch727
-rw-r--r--gnu/packages/patches/icecat-bug-1415133.patch40
4 files changed, 787 insertions, 1 deletions
diff --git a/gnu/local.mk b/gnu/local.mk
index 459112fc57..84483da999 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -744,6 +744,8 @@ dist_patch_DATA =						\
   %D%/packages/patches/hurd-fix-eth-multiplexer-dependency.patch        \
   %D%/packages/patches/hydra-disable-darcs-test.patch		\
   %D%/packages/patches/icecat-avoid-bundled-libraries.patch	\
+  %D%/packages/patches/icecat-bug-1348660-pt5.patch		\
+  %D%/packages/patches/icecat-bug-1415133.patch			\
   %D%/packages/patches/icu4c-CVE-2017-7867-CVE-2017-7868.patch	\
   %D%/packages/patches/icu4c-CVE-2017-14952.patch		\
   %D%/packages/patches/icu4c-reset-keyword-list-iterator.patch	\
diff --git a/gnu/packages/gnuzilla.scm b/gnu/packages/gnuzilla.scm
index ca563777c6..93aaaa9c5b 100644
--- a/gnu/packages/gnuzilla.scm
+++ b/gnu/packages/gnuzilla.scm
@@ -463,7 +463,24 @@ standards.")
         (mozilla-patch "icecat-CVE-2017-7826-pt16.patch" "dd068f4e132a" "17qy9c1vfkz3pj6y8qmqbic73wrangsbdlylk2s54nbzhhp9cj1g")
         (mozilla-patch "icecat-CVE-2017-7826-pt17.patch" "e6bd533b57e9" "1mmqav9yhxd0j47yffcdykaqjibfwjsk0jn0f44099s87y8qn9zy")
         (mozilla-patch "icecat-CVE-2017-7826-pt18.patch" "2a87fb6b9c07" "0z0scw4y1vqhqkbw1ag14g8xrif14l95x7fd50q2sw425lli29lc")
-        (mozilla-patch "icecat-bug-1404910.patch"        "5007f2472f64" "0ns1l4yipwbb52sps2xzg30qd1rkpwykxq4chjg3wllhmcxbvvpw")))
+        (mozilla-patch "icecat-bug-1404910.patch"        "5007f2472f64" "0ns1l4yipwbb52sps2xzg30qd1rkpwykxq4chjg3wllhmcxbvvpw")
+        (mozilla-patch "icecat-CVE-2017-7830.patch"      "04e3b5c1f0b2" "0nmv3jnx94ykxg64xkiwc8kx4df8zw7y5yzjnxz1sll2v88b9hmf")
+        (mozilla-patch "icecat-CVE-2017-7828-pt2.patch"  "2f48c03d9b3f" "16qdy3rahmkhsjnzqjcgzg1a4k7czd40m04gs9i75cd88kbripri")
+        (mozilla-patch "icecat-bug-1348660-pt1.patch"    "a352bfcbaf55" "1j3kxnhci9fh3lj8rizbcfv8xzn5kikxwpfy8a091d51sdn20873")
+        (mozilla-patch "icecat-bug-1348660-pt2.patch"    "57f43e2ab9b5" "1jva4y79zb85npak3mddrx5rsf4mxczb314kcr8yhlkwqv0nx5sp")
+        (mozilla-patch "icecat-bug-1348660-pt3.patch"    "917d65bb8896" "0k29y8i96lanqjjm6vybg0s6gjbk1mz5bfnga6aj1g0hnb7c3s8d")
+        (mozilla-patch "icecat-bug-1348660-pt4.patch"    "28934912eede" "1mhxw26050l3d09n8w912a86df87afcshvsk9k1k375anfk0927x")
+        (search-patch  "icecat-bug-1348660-pt5.patch")
+        (mozilla-patch "icecat-bug-1348660-pt6.patch"    "556ff3bfb9fc" "0kckjc8jp885xfaiwx2b9qnk1plqjhi0mwhjjcmfajvh3l3mrl8h")
+        (mozilla-patch "icecat-bug-1350564.patch"        "2abf26abb2a2" "0axdzp9g9k74wpkwrsdx263h01sv9bd3rarhhl68xnvc7n6i45lx")
+        (mozilla-patch "icecat-bug-1404787.patch"        "8335e1d7b140" "17d7kb8ginzflhdkrbi60vh2b907spbzmvwih7a595gqpihmnqqn")
+        (mozilla-patch "icecat-CVE-2017-7826-pt19.patch" "de336078d36b" "0gyzbap8hr1iywk0x2x0h7z7zp7q89hi56h8c03vvc7771dkvjkf")
+        (mozilla-patch "icecat-bug-1047098-pt1.patch"    "088577f0c46e" "0y3sz6kx07ls7jsvhqhhrl6v69a94wqvv3lz7hnplah23y06h17z")
+        (mozilla-patch "icecat-bug-1047098-pt2.patch"    "c7e3abf74023" "11dcjzx56v4yb2dvm23j2g86q8yva2hc69lmb7s5w18l6ygwwhzr")
+        (mozilla-patch "icecat-bug-1047098-pt3.patch"    "36bd15d14c5a" "0cb3l3hpsgk674f08kfamxhqfga3ah5v904gpxq9ag006vzd2cxz")
+        (mozilla-patch "icecat-bug-1404105.patch"        "2909ba991f31" "126vssj57dc800347f075wlnjzcwamnxxmgxl9w78jpb0hj9gf16")
+        (search-patch  "icecat-bug-1415133.patch")
+        (mozilla-patch "icecat-bug-1355576.patch"        "cf34a0574e58" "1z7sa1d12hypgivm5xxn32s58afpjcij97jvnafcgnfvxywrgr1m")))
       (modules '((guix build utils)))
       (snippet
        '(begin
diff --git a/gnu/packages/patches/icecat-bug-1348660-pt5.patch b/gnu/packages/patches/icecat-bug-1348660-pt5.patch
new file mode 100644
index 0000000000..b0bede3b38
--- /dev/null
+++ b/gnu/packages/patches/icecat-bug-1348660-pt5.patch
@@ -0,0 +1,727 @@
+This is a subset of the following changeset from upstream:
+  https://hg.mozilla.org/releases/mozilla-esr52/raw-rev/5e07bd37ac61
+
+This excludes all test code from that changeset, including a GIT binary patch
+that is not supported by Guix's patch-and-repack mechanism.
+
+# HG changeset patch
+# User Jan Varga <jan.varga@gmail.com>
+# Date 1490181244 -3600
+# Node ID 5e07bd37ac6162f218dfe03ed83b5dcca9653b68
+# Parent  28934912eede9e14895baf4af7575ca9639f59ee
+Bug 1348660 - Part 5: Implement a method to retrieve usage data for all origins at once. r=btseng, a=lizzard
+
+diff --git a/dom/quota/ActorsChild.cpp b/dom/quota/ActorsChild.cpp
+--- a/dom/quota/ActorsChild.cpp
++++ b/dom/quota/ActorsChild.cpp
+@@ -137,16 +137,52 @@ QuotaUsageRequestChild::HandleResponse(n
+   AssertIsOnOwningThread();
+   MOZ_ASSERT(NS_FAILED(aResponse));
+   MOZ_ASSERT(mRequest);
+ 
+   mRequest->SetError(aResponse);
+ }
+ 
+ void
++QuotaUsageRequestChild::HandleResponse(const nsTArray<OriginUsage>& aResponse)
++{
++  AssertIsOnOwningThread();
++  MOZ_ASSERT(mRequest);
++
++  RefPtr<nsVariant> variant = new nsVariant();
++
++  if (aResponse.IsEmpty()) {
++    variant->SetAsEmptyArray();
++  } else {
++    nsTArray<RefPtr<UsageResult>> usageResults;
++
++    const uint32_t count = aResponse.Length();
++
++    usageResults.SetCapacity(count);
++
++    for (uint32_t index = 0; index < count; index++) {
++      auto& originUsage = aResponse[index];
++
++      RefPtr<UsageResult> usageResult = new UsageResult(originUsage.origin(),
++                                                        originUsage.persisted(),
++                                                        originUsage.usage());
++
++      usageResults.AppendElement(usageResult.forget());
++    }
++
++    variant->SetAsArray(nsIDataType::VTYPE_INTERFACE_IS,
++                        &NS_GET_IID(nsIQuotaUsageResult),
++                        usageResults.Length(),
++                        static_cast<void*>(usageResults.Elements()));
++  }
++
++  mRequest->SetResult(variant);
++}
++
++void
+ QuotaUsageRequestChild::HandleResponse(const OriginUsageResponse& aResponse)
+ {
+   AssertIsOnOwningThread();
+   MOZ_ASSERT(mRequest);
+ 
+   RefPtr<OriginUsageResult> result =
+     new OriginUsageResult(aResponse.usage(),
+                           aResponse.fileUsage(),
+@@ -177,16 +213,20 @@ QuotaUsageRequestChild::Recv__delete__(c
+   AssertIsOnOwningThread();
+   MOZ_ASSERT(mRequest);
+ 
+   switch (aResponse.type()) {
+     case UsageRequestResponse::Tnsresult:
+       HandleResponse(aResponse.get_nsresult());
+       break;
+ 
++    case UsageRequestResponse::TAllUsageResponse:
++      HandleResponse(aResponse.get_AllUsageResponse().originUsages());
++      break;
++
+     case UsageRequestResponse::TOriginUsageResponse:
+       HandleResponse(aResponse.get_OriginUsageResponse());
+       break;
+ 
+     default:
+       MOZ_CRASH("Unknown response type!");
+   }
+ 
+diff --git a/dom/quota/ActorsChild.h b/dom/quota/ActorsChild.h
+--- a/dom/quota/ActorsChild.h
++++ b/dom/quota/ActorsChild.h
+@@ -93,16 +93,19 @@ private:
+ 
+   // Only destroyed by QuotaChild.
+   ~QuotaUsageRequestChild();
+ 
+   void
+   HandleResponse(nsresult aResponse);
+ 
+   void
++  HandleResponse(const nsTArray<OriginUsage>& aResponse);
++
++  void
+   HandleResponse(const OriginUsageResponse& aResponse);
+ 
+   // IPDL methods are only called by IPDL.
+   virtual void
+   ActorDestroy(ActorDestroyReason aWhy) override;
+ 
+   virtual bool
+   Recv__delete__(const UsageRequestResponse& aResponse) override;
+diff --git a/dom/quota/ActorsParent.cpp b/dom/quota/ActorsParent.cpp
+--- a/dom/quota/ActorsParent.cpp
++++ b/dom/quota/ActorsParent.cpp
+@@ -1039,16 +1039,42 @@ private:
+   // IPDL methods.
+   void
+   ActorDestroy(ActorDestroyReason aWhy) override;
+ 
+   bool
+   RecvCancel() override;
+ };
+ 
++class GetUsageOp final
++  : public QuotaUsageRequestBase
++{
++  nsTArray<OriginUsage> mOriginUsages;
++  nsDataHashtable<nsCStringHashKey, uint32_t> mOriginUsagesIndex;
++
++  bool mGetAll;
++
++public:
++  explicit GetUsageOp(const UsageRequestParams& aParams);
++
++private:
++  ~GetUsageOp()
++  { }
++
++  nsresult
++  TraverseRepository(QuotaManager* aQuotaManager,
++                     PersistenceType aPersistenceType);
++
++  nsresult
++  DoDirectoryWork(QuotaManager* aQuotaManager) override;
++
++  void
++  GetResponse(UsageRequestResponse& aResponse) override;
++};
++
+ class GetOriginUsageOp final
+   : public QuotaUsageRequestBase
+ {
+   // If mGetGroupUsage is false, we use mUsageInfo to record the origin usage
+   // and the file usage. Otherwise, we use it to record the group usage and the
+   // limit.
+   UsageInfo mUsageInfo;
+ 
+@@ -5693,16 +5719,20 @@ PQuotaUsageRequestParent*
+ Quota::AllocPQuotaUsageRequestParent(const UsageRequestParams& aParams)
+ {
+   AssertIsOnBackgroundThread();
+   MOZ_ASSERT(aParams.type() != UsageRequestParams::T__None);
+ 
+   RefPtr<QuotaUsageRequestBase> actor;
+ 
+   switch (aParams.type()) {
++    case UsageRequestParams::TAllUsageParams:
++      actor = new GetUsageOp(aParams);
++      break;
++
+     case UsageRequestParams::TOriginUsageParams:
+       actor = new GetOriginUsageOp(aParams);
+       break;
+ 
+     default:
+       MOZ_CRASH("Should never get here!");
+   }
+ 
+@@ -6033,16 +6063,189 @@ QuotaUsageRequestBase::RecvCancel()
+   if (mCanceled.exchange(true)) {
+     NS_WARNING("Canceled more than once?!");
+     return false;
+   }
+ 
+   return true;
+ }
+ 
++GetUsageOp::GetUsageOp(const UsageRequestParams& aParams)
++  : mGetAll(aParams.get_AllUsageParams().getAll())
++{
++  AssertIsOnOwningThread();
++  MOZ_ASSERT(aParams.type() == UsageRequestParams::TAllUsageParams);
++}
++
++nsresult
++GetUsageOp::TraverseRepository(QuotaManager* aQuotaManager,
++                               PersistenceType aPersistenceType)
++{
++  AssertIsOnIOThread();
++  MOZ_ASSERT(aQuotaManager);
++
++  nsresult rv;
++
++  nsCOMPtr<nsIFile> directory =
++    do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  rv = directory->InitWithPath(aQuotaManager->GetStoragePath(aPersistenceType));
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  bool exists;
++  rv = directory->Exists(&exists);
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  if (!exists) {
++    return NS_OK;
++  }
++
++  nsCOMPtr<nsISimpleEnumerator> entries;
++  rv = directory->GetDirectoryEntries(getter_AddRefs(entries));
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  bool persistent = aPersistenceType == PERSISTENCE_TYPE_PERSISTENT;
++
++  bool hasMore;
++  while (NS_SUCCEEDED((rv = entries->HasMoreElements(&hasMore))) &&
++         hasMore && !mCanceled) {
++    nsCOMPtr<nsISupports> entry;
++    rv = entries->GetNext(getter_AddRefs(entry));
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return rv;
++    }
++
++    nsCOMPtr<nsIFile> originDir = do_QueryInterface(entry);
++    MOZ_ASSERT(originDir);
++
++    bool isDirectory;
++    rv = originDir->IsDirectory(&isDirectory);
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return rv;
++    }
++
++    if (!isDirectory) {
++      nsString leafName;
++      rv = originDir->GetLeafName(leafName);
++      if (NS_WARN_IF(NS_FAILED(rv))) {
++        return rv;
++      }
++
++      if (!leafName.EqualsLiteral(DSSTORE_FILE_NAME)) {
++        QM_WARNING("Something (%s) in the repository that doesn't belong!",
++                   NS_ConvertUTF16toUTF8(leafName).get());
++      }
++      continue;
++    }
++
++    int64_t timestamp;
++    nsCString suffix;
++    nsCString group;
++    nsCString origin;
++    bool isApp;
++    rv = aQuotaManager->GetDirectoryMetadata2WithRestore(originDir,
++                                                         persistent,
++                                                         &timestamp,
++                                                         suffix,
++                                                         group,
++                                                         origin,
++                                                         &isApp);
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return rv;
++    }
++
++    if (!mGetAll &&
++        aQuotaManager->IsOriginWhitelistedForPersistentStorage(origin)) {
++      continue;
++    }
++
++    OriginUsage* originUsage;
++
++    // We can't store pointers to OriginUsage objects in the hashtable
++    // since AppendElement() reallocates its internal array buffer as number
++    // of elements grows.
++    uint32_t index;
++    if (mOriginUsagesIndex.Get(origin, &index)) {
++      originUsage = &mOriginUsages[index];
++    } else {
++      index = mOriginUsages.Length();
++
++      originUsage = mOriginUsages.AppendElement();
++
++      originUsage->origin() = origin;
++      originUsage->persisted() = false;
++      originUsage->usage() = 0;
++
++      mOriginUsagesIndex.Put(origin, index);
++    }
++
++    UsageInfo usageInfo;
++    rv = GetUsageForOrigin(aQuotaManager,
++                           aPersistenceType,
++                           group,
++                           origin,
++                           isApp,
++                           &usageInfo);
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return rv;
++    }
++
++    originUsage->usage() = originUsage->usage() + usageInfo.TotalUsage();
++  }
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  return NS_OK;
++}
++
++nsresult
++GetUsageOp::DoDirectoryWork(QuotaManager* aQuotaManager)
++{
++  AssertIsOnIOThread();
++
++  PROFILER_LABEL("Quota", "GetUsageOp::DoDirectoryWork",
++                 js::ProfileEntry::Category::OTHER);
++
++  nsresult rv;
++
++  for (const PersistenceType type : kAllPersistenceTypes) {
++    rv = TraverseRepository(aQuotaManager, type);
++    if (NS_WARN_IF(NS_FAILED(rv))) {
++      return rv;
++    }
++  }
++
++  return NS_OK;
++}
++
++void
++GetUsageOp::GetResponse(UsageRequestResponse& aResponse)
++{
++  AssertIsOnOwningThread();
++
++  aResponse = AllUsageResponse();
++
++  if (!mOriginUsages.IsEmpty()) {
++    nsTArray<OriginUsage>& originUsages =
++      aResponse.get_AllUsageResponse().originUsages();
++
++    mOriginUsages.SwapElements(originUsages);
++  }
++}
++
+ GetOriginUsageOp::GetOriginUsageOp(const UsageRequestParams& aParams)
+   : mParams(aParams.get_OriginUsageParams())
+   , mGetGroupUsage(aParams.get_OriginUsageParams().getGroupUsage())
+ {
+   AssertIsOnOwningThread();
+   MOZ_ASSERT(aParams.type() == UsageRequestParams::TOriginUsageParams);
+ }
+ 
+diff --git a/dom/quota/PQuota.ipdl b/dom/quota/PQuota.ipdl
+--- a/dom/quota/PQuota.ipdl
++++ b/dom/quota/PQuota.ipdl
+@@ -12,24 +12,30 @@ include "mozilla/dom/quota/Serialization
+ 
+ using mozilla::dom::quota::PersistenceType
+   from "mozilla/dom/quota/PersistenceType.h";
+ 
+ namespace mozilla {
+ namespace dom {
+ namespace quota {
+ 
++struct AllUsageParams
++{
++  bool getAll;
++};
++
+ struct OriginUsageParams
+ {
+   PrincipalInfo principalInfo;
+   bool getGroupUsage;
+ };
+ 
+ union UsageRequestParams
+ {
++  AllUsageParams;
+   OriginUsageParams;
+ };
+ 
+ struct ClearOriginParams
+ {
+   PrincipalInfo principalInfo;
+   PersistenceType persistenceType;
+   bool persistenceTypeIsExplicit;
+diff --git a/dom/quota/PQuotaUsageRequest.ipdl b/dom/quota/PQuotaUsageRequest.ipdl
+--- a/dom/quota/PQuotaUsageRequest.ipdl
++++ b/dom/quota/PQuotaUsageRequest.ipdl
+@@ -3,26 +3,39 @@
+  * You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ include protocol PQuota;
+ 
+ namespace mozilla {
+ namespace dom {
+ namespace quota {
+ 
++struct OriginUsage
++{
++  nsCString origin;
++  bool persisted;
++  uint64_t usage;
++};
++
++struct AllUsageResponse
++{
++  OriginUsage[] originUsages;
++};
++
+ struct OriginUsageResponse
+ {
+   uint64_t usage;
+   uint64_t fileUsage;
+   uint64_t limit;
+ };
+ 
+ union UsageRequestResponse
+ {
+   nsresult;
++  AllUsageResponse;
+   OriginUsageResponse;
+ };
+ 
+ protocol PQuotaUsageRequest
+ {
+   manager PQuota;
+ 
+ parent:
+diff --git a/dom/quota/QuotaManagerService.cpp b/dom/quota/QuotaManagerService.cpp
+--- a/dom/quota/QuotaManagerService.cpp
++++ b/dom/quota/QuotaManagerService.cpp
+@@ -490,16 +490,41 @@ QuotaManagerService::RemoveIdleObserver(
+ 
+ NS_IMPL_ADDREF(QuotaManagerService)
+ NS_IMPL_RELEASE_WITH_DESTROY(QuotaManagerService, Destroy())
+ NS_IMPL_QUERY_INTERFACE(QuotaManagerService,
+                         nsIQuotaManagerService,
+                         nsIObserver)
+ 
+ NS_IMETHODIMP
++QuotaManagerService::GetUsage(nsIQuotaUsageCallback* aCallback,
++                              bool aGetAll,
++                              nsIQuotaUsageRequest** _retval)
++{
++  MOZ_ASSERT(NS_IsMainThread());
++  MOZ_ASSERT(aCallback);
++
++  RefPtr<UsageRequest> request = new UsageRequest(aCallback);
++
++  AllUsageParams params;
++
++  params.getAll() = aGetAll;
++
++  nsAutoPtr<PendingRequestInfo> info(new UsageRequestInfo(request, params));
++
++  nsresult rv = InitiateRequest(info);
++  if (NS_WARN_IF(NS_FAILED(rv))) {
++    return rv;
++  }
++
++  request.forget(_retval);
++  return NS_OK;
++}
++
++NS_IMETHODIMP
+ QuotaManagerService::GetUsageForPrincipal(nsIPrincipal* aPrincipal,
+                                           nsIQuotaUsageCallback* aCallback,
+                                           bool aGetGroupUsage,
+                                           nsIQuotaUsageRequest** _retval)
+ {
+   MOZ_ASSERT(NS_IsMainThread());
+   MOZ_ASSERT(aPrincipal);
+   MOZ_ASSERT(aCallback);
+diff --git a/dom/quota/QuotaRequests.cpp b/dom/quota/QuotaRequests.cpp
+--- a/dom/quota/QuotaRequests.cpp
++++ b/dom/quota/QuotaRequests.cpp
+@@ -86,16 +86,25 @@ RequestBase::GetResultCode(nsresult* aRe
+   if (!mHaveResultOrErrorCode) {
+     return NS_ERROR_FAILURE;
+   }
+ 
+   *aResultCode = mResultCode;
+   return NS_OK;
+ }
+ 
++UsageRequest::UsageRequest(nsIQuotaUsageCallback* aCallback)
++  : mCallback(aCallback)
++  , mBackgroundActor(nullptr)
++  , mCanceled(false)
++{
++  AssertIsOnOwningThread();
++  MOZ_ASSERT(aCallback);
++}
++
+ UsageRequest::UsageRequest(nsIPrincipal* aPrincipal,
+                            nsIQuotaUsageCallback* aCallback)
+   : RequestBase(aPrincipal)
+   , mCallback(aCallback)
+   , mBackgroundActor(nullptr)
+   , mCanceled(false)
+ {
+   AssertIsOnOwningThread();
+diff --git a/dom/quota/QuotaRequests.h b/dom/quota/QuotaRequests.h
+--- a/dom/quota/QuotaRequests.h
++++ b/dom/quota/QuotaRequests.h
+@@ -73,16 +73,18 @@ class UsageRequest final
+ 
+   nsCOMPtr<nsIVariant> mResult;
+ 
+   QuotaUsageRequestChild* mBackgroundActor;
+ 
+   bool mCanceled;
+ 
+ public:
++  explicit UsageRequest(nsIQuotaUsageCallback* aCallback);
++
+   UsageRequest(nsIPrincipal* aPrincipal,
+                nsIQuotaUsageCallback* aCallback);
+ 
+   void
+   SetBackgroundActor(QuotaUsageRequestChild* aBackgroundActor);
+ 
+   void
+   ClearBackgroundActor()
+diff --git a/dom/quota/QuotaResults.cpp b/dom/quota/QuotaResults.cpp
+--- a/dom/quota/QuotaResults.cpp
++++ b/dom/quota/QuotaResults.cpp
+@@ -5,16 +5,53 @@
+  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ 
+ #include "QuotaResults.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ namespace quota {
+ 
++UsageResult::UsageResult(const nsACString& aOrigin,
++                         bool aPersisted,
++                         uint64_t aUsage)
++  : mOrigin(aOrigin)
++  , mUsage(aUsage)
++  , mPersisted(aPersisted)
++{
++}
++
++NS_IMPL_ISUPPORTS(UsageResult,
++                  nsIQuotaUsageResult)
++
++NS_IMETHODIMP
++UsageResult::GetOrigin(nsACString& aOrigin)
++{
++  aOrigin = mOrigin;
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++UsageResult::GetPersisted(bool* aPersisted)
++{
++  MOZ_ASSERT(aPersisted);
++
++  *aPersisted = mPersisted;
++  return NS_OK;
++}
++
++NS_IMETHODIMP
++UsageResult::GetUsage(uint64_t* aUsage)
++{
++  MOZ_ASSERT(aUsage);
++
++  *aUsage = mUsage;
++  return NS_OK;
++}
++
+ OriginUsageResult::OriginUsageResult(uint64_t aUsage,
+                                      uint64_t aFileUsage,
+                                      uint64_t aLimit)
+   : mUsage(aUsage)
+   , mFileUsage(aFileUsage)
+   , mLimit(aLimit)
+ {
+ }
+diff --git a/dom/quota/QuotaResults.h b/dom/quota/QuotaResults.h
+--- a/dom/quota/QuotaResults.h
++++ b/dom/quota/QuotaResults.h
+@@ -8,16 +8,36 @@
+ #define mozilla_dom_quota_QuotaResults_h
+ 
+ #include "nsIQuotaResults.h"
+ 
+ namespace mozilla {
+ namespace dom {
+ namespace quota {
+ 
++class UsageResult
++  : public nsIQuotaUsageResult
++{
++  nsCString mOrigin;
++  uint64_t mUsage;
++  bool mPersisted;
++
++public:
++  UsageResult(const nsACString& aOrigin,
++              bool aPersisted,
++              uint64_t aUsage);
++
++private:
++  virtual ~UsageResult()
++  { }
++
++  NS_DECL_ISUPPORTS
++  NS_DECL_NSIQUOTAUSAGERESULT
++};
++
+ class OriginUsageResult
+   : public nsIQuotaOriginUsageResult
+ {
+   uint64_t mUsage;
+   uint64_t mFileUsage;
+   uint64_t mLimit;
+ 
+ public:
+diff --git a/dom/quota/nsIQuotaManagerService.idl b/dom/quota/nsIQuotaManagerService.idl
+--- a/dom/quota/nsIQuotaManagerService.idl
++++ b/dom/quota/nsIQuotaManagerService.idl
+@@ -10,16 +10,31 @@ interface nsIPrincipal;
+ interface nsIQuotaRequest;
+ interface nsIQuotaUsageCallback;
+ interface nsIQuotaUsageRequest;
+ 
+ [scriptable, builtinclass, uuid(1b3d0a38-8151-4cf9-89fa-4f92c2ef0e7e)]
+ interface nsIQuotaManagerService : nsISupports
+ {
+   /**
++   * Schedules an asynchronous callback that will inspect all origins and
++   * return the total amount of disk space being used by storages for each
++   * origin separately.
++   *
++   * @param aCallback
++   *        The callback that will be called when the usage is available.
++   * @param aGetAll
++   *        An optional boolean to indicate inspection of all origins,
++   *        including internal ones.
++   */
++  [must_use] nsIQuotaUsageRequest
++  getUsage(in nsIQuotaUsageCallback aCallback,
++           [optional] in boolean aGetAll);
++
++  /**
+    * Schedules an asynchronous callback that will return the total amount of
+    * disk space being used by storages for the given origin.
+    *
+    * @param aPrincipal
+    *        A principal for the origin whose usage is being queried.
+    * @param aCallback
+    *        The callback that will be called when the usage is available.
+    * @param aGetGroupUsage
+diff --git a/dom/quota/nsIQuotaRequests.idl b/dom/quota/nsIQuotaRequests.idl
+--- a/dom/quota/nsIQuotaRequests.idl
++++ b/dom/quota/nsIQuotaRequests.idl
+@@ -18,16 +18,17 @@ interface nsIQuotaRequestBase : nsISuppo
+ 
+   [must_use] readonly attribute nsresult resultCode;
+ };
+ 
+ [scriptable, uuid(166e28e6-cf6d-4927-a6d7-b51bca9d3469)]
+ interface nsIQuotaUsageRequest : nsIQuotaRequestBase
+ {
+   // The result can contain one of these types:
++  //   array of nsIQuotaUsageResult
+   //   nsIQuotaOriginUsageResult
+   [must_use] readonly attribute nsIVariant result;
+ 
+   attribute nsIQuotaUsageCallback callback;
+ 
+   [must_use] void
+   cancel();
+ };
+diff --git a/dom/quota/nsIQuotaResults.idl b/dom/quota/nsIQuotaResults.idl
+--- a/dom/quota/nsIQuotaResults.idl
++++ b/dom/quota/nsIQuotaResults.idl
+@@ -1,16 +1,26 @@
+ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+ /* vim: set ts=2 et sw=2 tw=80: */
+ /* 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 "nsISupports.idl"
+ 
++[scriptable, function, uuid(d8c9328b-9aa8-4f5d-90e6-482de4a6d5b8)]
++interface nsIQuotaUsageResult : nsISupports
++{
++  readonly attribute ACString origin;
++
++  readonly attribute boolean persisted;
++
++  readonly attribute unsigned long long usage;
++};
++
+ [scriptable, function, uuid(96df03d2-116a-493f-bb0b-118c212a6b32)]
+ interface nsIQuotaOriginUsageResult : nsISupports
+ {
+   readonly attribute unsigned long long usage;
+ 
+   readonly attribute unsigned long long fileUsage;
+ 
+   readonly attribute unsigned long long limit;
+
diff --git a/gnu/packages/patches/icecat-bug-1415133.patch b/gnu/packages/patches/icecat-bug-1415133.patch
new file mode 100644
index 0000000000..4e322d21fb
--- /dev/null
+++ b/gnu/packages/patches/icecat-bug-1415133.patch
@@ -0,0 +1,40 @@
+Based on:
+  https://hg.mozilla.org/releases/mozilla-esr52/raw-rev/22fe3ff3f923
+
+Adapted to apply cleanly to IceCat.
+
+# HG changeset patch
+# User Marco Bonardo <mbonardo@mozilla.com>
+# Date 1510052455 -3600
+# Node ID 22fe3ff3f92358596521f7155ddc512006022207
+# Parent  2909ba991f3134f9fbf4859cf08582f1c9845594
+Bug 1415133 - Downgrades from 55+ to ESR lose bookmarks. r=past a=lizzard
+
+MozReview-Commit-ID: 44Rw7m1FP4h
+
+diff --git a/toolkit/components/places/Database.cpp b/toolkit/components/places/Database.cpp
+--- a/toolkit/components/places/Database.cpp
++++ b/toolkit/components/places/Database.cpp
+@@ -761,16 +761,21 @@ Database::InitSchema(bool* aDatabaseMigr
+     // 2. implement a method that performs upgrade to your version from the
+     //    previous one.
+     //
+     // NOTE: The downgrade process is pretty much complicated by the fact old
+     //       versions cannot know what a new version is going to implement.
+     //       The only thing we will do for downgrades is setting back the schema
+     //       version, so that next upgrades will run again the migration step.
+ 
++    if (currentSchemaVersion > 36) {
++      // These versions are not downgradable.
++      return NS_ERROR_FILE_CORRUPTED;
++    }
++
+     if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
+       *aDatabaseMigrated = true;
+ 
+       if (currentSchemaVersion < 11) {
+         // These are versions older than IceCat 4 that are not supported
+         // anymore.  In this case it's safer to just replace the database.
+         return NS_ERROR_FILE_CORRUPTED;
+       }
+