Bug 1305563 - Expose `PlacesUtils.history.hashURL`. draft
authorKit Cambridge <kit@yakshaving.ninja>
Wed, 16 Aug 2017 16:01:40 -0700
changeset 651837 f88d80a97308a9bd9b998e71338278f1a70adc91
parent 650941 7c50f0c999c5bf8ee915261997597a5a9b8fb2ae
child 651838 d5f50320a46852ef528e479e03a02abe8a960463
push id75824
push userbmo:kit@mozilla.com
push dateThu, 24 Aug 2017 02:36:08 +0000
bugs1305563
milestone57.0a1
Bug 1305563 - Expose `PlacesUtils.history.hashURL`. MozReview-Commit-ID: C4Zj4FyMZpq
toolkit/components/places/Helpers.cpp
toolkit/components/places/Helpers.h
toolkit/components/places/SQLFunctions.cpp
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavHistory.cpp
--- a/toolkit/components/places/Helpers.cpp
+++ b/toolkit/components/places/Helpers.cpp
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "Helpers.h"
 #include "mozIStorageError.h"
 #include "prio.h"
 #include "nsString.h"
 #include "nsNavHistory.h"
 #include "mozilla/Base64.h"
+#include "mozilla/HashFunctions.h"
 #include "mozilla/Services.h"
 
 // The length of guids that are used by history and bookmarks.
 #define GUID_LENGTH 12
 
 namespace mozilla {
 namespace places {
 
@@ -306,16 +307,58 @@ RoundToMilliseconds(PRTime aTime) {
   return aTime - (aTime % PR_USEC_PER_MSEC);
 }
 
 PRTime
 RoundedPRNow() {
   return RoundToMilliseconds(PR_Now());
 }
 
+nsresult
+HashURL(const nsAString& aSpec, const nsACString& aMode, uint64_t *_hash)
+{
+  NS_ENSURE_ARG_POINTER(_hash);
+
+  if (aMode.IsEmpty()) {
+    // URI-like strings (having a prefix before a colon), are handled specially,
+    // as a 48 bit hash, where first 16 bits are the prefix hash, while the
+    // other 32 are the string hash.
+    // The 16 bits have been decided based on the fact hashing all of the IANA
+    // known schemes, plus "places", does not generate collisions.
+    nsAString::const_iterator start, tip, end;
+    aSpec.BeginReading(tip);
+    start = tip;
+    aSpec.EndReading(end);
+    if (FindInReadable(NS_LITERAL_STRING(":"), tip, end)) {
+      const nsDependentSubstring& prefix = Substring(start, tip);
+      uint64_t prefixHash = static_cast<uint64_t>(HashString(prefix) & 0x0000FFFF);
+      // The second half of the url is more likely to be unique, so we add it.
+      uint32_t srcHash = HashString(aSpec);
+      *_hash = (prefixHash << 32) + srcHash;
+    } else {
+      *_hash = HashString(aSpec);
+    }
+    return NS_OK;
+  }
+  if (aMode.Equals(NS_LITERAL_CSTRING("prefix_lo"))) {
+    // Keep only 16 bits.
+    *_hash = static_cast<uint64_t>(HashString(aSpec) & 0x0000FFFF) << 32;
+    return NS_OK;
+  }
+  if (aMode.Equals(NS_LITERAL_CSTRING("prefix_hi"))) {
+    // Keep only 16 bits.
+    *_hash = static_cast<uint64_t>(HashString(aSpec) & 0x0000FFFF) << 32;
+    // Make this a prefix upper bound by filling the lowest 32 bits.
+    *_hash +=  0xFFFFFFFF;
+    return NS_OK;
+  }
+
+  return NS_ERROR_FAILURE;
+}
+
 bool
 GetHiddenState(bool aIsRedirect,
                uint32_t aTransitionType)
 {
   return aTransitionType == nsINavHistoryService::TRANSITION_FRAMED_LINK ||
          aTransitionType == nsINavHistoryService::TRANSITION_EMBED ||
          aIsRedirect;
 }
--- a/toolkit/components/places/Helpers.h
+++ b/toolkit/components/places/Helpers.h
@@ -169,16 +169,19 @@ PRTime RoundToMilliseconds(PRTime aTime)
 
 /**
  * Round down PR_Now() to milliseconds precision.
  *
  * @return @see PR_Now, RoundToMilliseconds.
  */
 PRTime RoundedPRNow();
 
+nsresult HashURL(const nsAString& aSpec, const nsACString& aMode,
+                 uint64_t *_hash);
+
 /**
  * Used to finalize a statementCache on a specified thread.
  */
 template<typename StatementType>
 class FinalizeStatementCacheProxy : public Runnable
 {
 public:
   /**
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -13,17 +13,16 @@
 #include "nsMathUtils.h"
 #include "nsUnicodeProperties.h"
 #include "nsUTF8Utils.h"
 #include "nsINavHistoryService.h"
 #include "nsPrintfCString.h"
 #include "nsNavHistory.h"
 #include "mozilla/Likely.h"
 #include "nsVariant.h"
-#include "mozilla/HashFunctions.h"
 
 // Maximum number of chars to search through.
 // MatchAutoCompleteFunction won't look for matches over this threshold.
 #define MAX_CHARS_TO_SEARCH_THROUGH 255
 
 using namespace mozilla::storage;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -1007,49 +1006,20 @@ namespace places {
     nsString str;
     aArguments->GetString(0, str);
     nsAutoCString mode;
     if (numEntries > 1) {
       aArguments->GetUTF8String(1, mode);
     }
 
     RefPtr<nsVariant> result = new nsVariant();
-    if (mode.IsEmpty()) {
-      // URI-like strings (having a prefix before a colon), are handled specially,
-      // as a 48 bit hash, where first 16 bits are the prefix hash, while the
-      // other 32 are the string hash.
-      // The 16 bits have been decided based on the fact hashing all of the IANA
-      // known schemes, plus "places", does not generate collisions.
-      nsAString::const_iterator start, tip, end;
-      str.BeginReading(tip);
-      start = tip;
-      str.EndReading(end);
-      if (FindInReadable(NS_LITERAL_STRING(":"), tip, end)) {
-        const nsDependentSubstring& prefix = Substring(start, tip);
-        uint64_t prefixHash = static_cast<uint64_t>(HashString(prefix) & 0x0000FFFF);
-        // The second half of the url is more likely to be unique, so we add it.
-        uint32_t srcHash = HashString(str);
-        uint64_t hash = (prefixHash << 32) + srcHash;
-        result->SetAsInt64(hash);
-      } else {
-        uint32_t hash = HashString(str);
-        result->SetAsInt64(hash);
-      }
-    } else if (mode.Equals(NS_LITERAL_CSTRING("prefix_lo"))) {
-      // Keep only 16 bits.
-      uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
-      result->SetAsInt64(hash);
-    } else if (mode.Equals(NS_LITERAL_CSTRING("prefix_hi"))) {
-      // Keep only 16 bits.
-      uint64_t hash = static_cast<uint64_t>(HashString(str) & 0x0000FFFF) << 32;
-      // Make this a prefix upper bound by filling the lowest 32 bits.
-      hash +=  0xFFFFFFFF;
-      result->SetAsInt64(hash);
-    } else {
-      return NS_ERROR_FAILURE;
-    }
+    uint64_t hash;
+    rv = HashURL(str, mode, &hash);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = result->SetAsInt64(hash);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     result.forget(_result);
     return NS_OK;
   }
 
 } // namespace places
 } // namespace mozilla
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -1431,16 +1431,18 @@ interface nsINavHistoryService : nsISupp
   void clearEmbedVisits();
 
   /**
    * Generate a guid.
    * Guids can be used for any places purposes (history, bookmarks, etc.)
    * Returns null if the generation of the guid failed.
    */
   ACString makeGuid();
+
+  uint64_t hashURL(in AString aSpec, [optional] in ACString mode);
 };
 
 /**
  * @see runInBatchMode of nsINavHistoryService/nsINavBookmarksService
  */
 [scriptable, function, uuid(5a5a9154-95ac-4e3d-90df-558816297407)]
 interface nsINavHistoryBatchCallback : nsISupports {
   void runBatched(in nsISupports aUserData);
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -3756,16 +3756,22 @@ NS_IMETHODIMP
 nsNavHistory::MakeGuid(nsACString& aGuid) {
   if (NS_FAILED(GenerateGUID(aGuid))) {
     MOZ_ASSERT(false, "Shouldn't fail to create a guid!");
     aGuid.SetIsVoid(true);
   }
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsNavHistory::HashURL(const nsAString& aSpec, const nsACString& aMode,
+                      uint64_t* aHash) {
+  return places::HashURL(aSpec, aMode, aHash);
+}
+
 // nsNavHistory::CheckIsRecentEvent
 //
 //    Sees if this URL happened "recently."
 //
 //    It is always removed from our recent list no matter what. It only counts
 //    as "recent" if the event happened more recently than our event
 //    threshold ago.