Bug 742776 - Use a case sensitive match for the URI path in inline autocomplete query.
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 19 Apr 2012 22:17:04 +0200
changeset 95313 853ae8c135f9e904c8c1d23ebf869af313bf0124
parent 95312 df8d8d06a7bd19decb85ea3a166b332cf449fff4
child 95314 4209594a01af72ea2e31a46c69c9750f17e2725d
push idunknown
push userunknown
push dateunknown
bugs742776
milestone14.0a1
Bug 742776 - Use a case sensitive match for the URI path in inline autocomplete query. r=gavin a=desktop-only
toolkit/components/places/SQLFunctions.cpp
toolkit/components/places/SQLFunctions.h
toolkit/components/places/mozIPlacesAutoComplete.idl
toolkit/components/places/nsPlacesAutoComplete.js
toolkit/components/places/tests/inline/test_casing.js
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -315,25 +315,38 @@ namespace places {
     // We don't need to check CaseInsensitiveUTF8CharsEqual's error condition
     // (stored in |dummy|), since the function will return false if it
     // encounters an error.
 
     return false;
   }
 
   /* static */
+  bool
+  MatchAutoCompleteFunction::findBeginningCaseSensitive(
+    const nsDependentCSubstring &aToken,
+    const nsACString &aSourceString)
+  {
+    NS_PRECONDITION(!aToken.IsEmpty(), "Don't search for an empty token!");
+
+    return StringBeginsWith(aSourceString, aToken);
+  }
+
+  /* static */
   MatchAutoCompleteFunction::searchFunctionPtr
   MatchAutoCompleteFunction::getSearchFunction(PRInt32 aBehavior)
   {
     switch (aBehavior) {
       case mozIPlacesAutoComplete::MATCH_ANYWHERE:
       case mozIPlacesAutoComplete::MATCH_ANYWHERE_UNMODIFIED:
         return findAnywhere;
       case mozIPlacesAutoComplete::MATCH_BEGINNING:
         return findBeginning;
+      case mozIPlacesAutoComplete::MATCH_BEGINNING_CASE_SENSITIVE:
+        return findBeginningCaseSensitive;
       case mozIPlacesAutoComplete::MATCH_BOUNDARY:
       default:
         return findOnBoundary;
     };
   }
 
   NS_IMPL_THREADSAFE_ISUPPORTS1(
     MatchAutoCompleteFunction,
--- a/toolkit/components/places/SQLFunctions.h
+++ b/toolkit/components/places/SQLFunctions.h
@@ -142,16 +142,28 @@ private:
    * @param aSourceString
    *        The string to search.
    * @return true if found, false otherwise.
    */
   static bool findBeginning(const nsDependentCSubstring &aToken,
                             const nsACString &aSourceString);
 
   /**
+   * Tests if aSourceString starts with aToken in a case sensitive way.
+   *
+   * @param aToken
+   *        The string to search for.
+   * @param aSourceString
+   *        The string to search.
+   * @return true if found, false otherwise.
+   */
+  static bool findBeginningCaseSensitive(const nsDependentCSubstring &aToken,
+                                         const nsACString &aSourceString);
+
+  /**
    * Searches aSourceString for aToken anywhere in the string in a case-
    * insensitive way.
    *
    * @param aToken
    *        The string to search for.
    * @param aSourceString
    *        The string to search.
    * @return true if found, false otherwise.
--- a/toolkit/components/places/mozIPlacesAutoComplete.idl
+++ b/toolkit/components/places/mozIPlacesAutoComplete.idl
@@ -74,16 +74,22 @@ interface mozIPlacesAutoComplete : nsISu
   const long MATCH_BEGINNING = 3;
 
   /**
    * Match anywhere in each searchable term without doing any transformation
    * or stripping on the underlying data.
    */
   const long MATCH_ANYWHERE_UNMODIFIED = 4;
 
+  /**
+   * Match only the beginning of each search term using a case sensitive
+   * comparator.
+   */
+  const long MATCH_BEGINNING_CASE_SENSITIVE = 5;
+
   //////////////////////////////////////////////////////////////////////////////
   //// Search Behavior Constants
 
   /**
    * Search through history.
    */
   const long BEHAVIOR_HISTORY = 1 << 0;
 
--- a/toolkit/components/places/nsPlacesAutoComplete.js
+++ b/toolkit/components/places/nsPlacesAutoComplete.js
@@ -71,16 +71,17 @@ const kTopicShutdown = "places-shutdown"
 const kPrefChanged = "nsPref:changed";
 
 // Match type constants.  These indicate what type of search function we should
 // be using.
 const MATCH_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE;
 const MATCH_BOUNDARY_ANYWHERE = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY_ANYWHERE;
 const MATCH_BOUNDARY = Ci.mozIPlacesAutoComplete.MATCH_BOUNDARY;
 const MATCH_BEGINNING = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING;
+const MATCH_BEGINNING_CASE_SENSITIVE = Ci.mozIPlacesAutoComplete.MATCH_BEGINNING_CASE_SENSITIVE;
 
 // AutoComplete index constants.  All AutoComplete queries will provide these
 // columns in this order.
 const kQueryIndexURL = 0;
 const kQueryIndexTitle = 1;
 const kQueryIndexFaviconURL = 2;
 const kQueryIndexBookmarked = 3;
 const kQueryIndexBookmarkTitle = 4;
@@ -1434,21 +1435,30 @@ urlInlineComplete.prototype = {
     // We don't need to search if we have no "/" separator, or if it's at
     // the end of the search text.
     if (lastSlashIndex == -1 ||
         lastSlashIndex == this._currentSearchString.length - 1) {
       this._finishSearch();
       return;
     }
 
+    // The URIs in the database are fixed up, so we can match on a lowercased
+    // host, but the path must be matched in a case sensitive way.
+    let pathIndex =
+      this._originalSearchString.indexOf("/", this._strippedPrefix.length);
+    this._currentSearchString = fixupSearchText(
+      this._originalSearchString.slice(0, pathIndex).toLowerCase() +
+      this._originalSearchString.slice(pathIndex)
+    );
+
     // Within the standard autocomplete query, we only search the beginning
     // of URLs for 1 result.
     let query = this._asyncQuery;
     let (params = query.params) {
-      params.matchBehavior = MATCH_BEGINNING;
+      params.matchBehavior = MATCH_BEGINNING_CASE_SENSITIVE;
       params.searchBehavior = Ci.mozIPlacesAutoComplete["BEHAVIOR_URL"];
       params.searchString = this._currentSearchString;
     }
 
     // Execute the async query
     let wrapper = new AutoCompleteStatementCallbackWrapper(this, this._db);
     this._pendingQuery = wrapper.executeAsync([query]);
   },
--- a/toolkit/components/places/tests/inline/test_casing.js
+++ b/toolkit/components/places/tests/inline/test_casing.js
@@ -9,26 +9,44 @@ add_autocomplete_test([
   function () {
     addBookmark({ url: "http://mozilla.org/test/" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 2",
   "mozilla.org/T",
-  { autoFilled: "mozilla.org/Test/", completed: "mozilla.org/test/" },
+  { autoFilled: "mozilla.org/T", completed: "mozilla.org/T" },
   function () {
     addBookmark({ url: "http://mozilla.org/test/" });
   }
 ]);
 
 add_autocomplete_test([
   "Searching for cased entry 3",
+  "mozilla.org/T",
+  { autoFilled: "mozilla.org/Test/", completed: "mozilla.org/Test/" },
+  function () {
+    addBookmark({ url: "http://mozilla.org/Test/" });
+  }
+]);
+
+add_autocomplete_test([
+  "Searching for cased entry 4",
   "mOzilla.org/t",
-  { autoFilled: "mOzilla.org/test/", completed: "mozilla.org/Test/" },
+  { autoFilled: "mOzilla.org/t", completed: "mOzilla.org/t" },
+  function () {
+    addBookmark({ url: "http://mozilla.org/Test/" });
+  },
+]);
+
+add_autocomplete_test([
+  "Searching for cased entry 5",
+  "mOzilla.org/T",
+  { autoFilled: "mOzilla.org/Test/", completed: "mozilla.org/Test/" },
   function () {
     addBookmark({ url: "http://mozilla.org/Test/" });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry",
   "http://mOz",
@@ -45,22 +63,40 @@ add_autocomplete_test([
   function () {
     addBookmark({ url: "http://www.mozilla.org/Test/" });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with path",
   "http://mOzilla.org/t",
-  { autoFilled: "http://mOzilla.org/test/", completed: "http://mozilla.org/Test/" },
+  { autoFilled: "http://mOzilla.org/t", completed: "http://mOzilla.org/t" },
+  function () {
+    addBookmark({ url: "http://mozilla.org/Test/" });
+  },
+]);
+
+add_autocomplete_test([
+  "Searching for untrimmed cased entry with path 2",
+  "http://mOzilla.org/T",
+  { autoFilled: "http://mOzilla.org/Test/", completed: "http://mozilla.org/Test/" },
   function () {
     addBookmark({ url: "http://mozilla.org/Test/" });
   },
 ]);
 
 add_autocomplete_test([
   "Searching for untrimmed cased entry with www and path",
   "http://www.mOzilla.org/t",
-  { autoFilled: "http://www.mOzilla.org/test/", completed: "http://www.mozilla.org/Test/" },
+  { autoFilled: "http://www.mOzilla.org/t", completed: "http://www.mOzilla.org/t" },
   function () {
     addBookmark({ url: "http://www.mozilla.org/Test/" });
   },
 ]);
+
+add_autocomplete_test([
+  "Searching for untrimmed cased entry with www and path 2",
+  "http://www.mOzilla.org/T",
+  { autoFilled: "http://www.mOzilla.org/Test/", completed: "http://www.mozilla.org/Test/" },
+  function () {
+    addBookmark({ url: "http://www.mozilla.org/Test/" });
+  },
+]);