Bug 1042519 - test. should result in a keyword lookup instead of an error page. r=bz, r=mak, a=sledru
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Fri, 25 Jul 2014 11:46:07 +0100
changeset 217405 c111b7cf29ff24c2ef39d0482cc685c2c5425af2
parent 217404 5ce3895d8dd87e6a03a64a9609c4455e61807f82
child 217406 05c1785ef9592ceb1e8f8f51da158667c3ab6983
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, mak, sledru
bugs1042519
milestone33.0a2
Bug 1042519 - test. should result in a keyword lookup instead of an error page. r=bz, r=mak, a=sledru Also taking the opportunity to rework the nsIURIFixupInfo interface to use more sensible booleans, and the relevant test to specify outcomes directly, instead of trying to use the same logic as the implementation to infer them from the input.
browser/base/content/browser.js
browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js
docshell/base/nsDefaultURIFixup.cpp
docshell/base/nsDefaultURIFixup.h
docshell/base/nsIURIFixup.idl
docshell/test/unit/test_nsDefaultURIFixup_info.js
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -790,16 +790,23 @@ function gKeywordURIFixup(fixupInfo, top
   // even if the DNS query takes forever
   let weakBrowser = Cu.getWeakReference(browser);
   browser = null;
 
   // Additionally, we need the host of the parsed url
   let hostName = alternativeURI.host;
   // and the ascii-only host for the pref:
   let asciiHost = alternativeURI.asciiHost;
+  // Normalize out a single trailing dot - NB: not using endsWith/lastIndexOf
+  // because we need to be sure this last dot is the *only* dot, too.
+  // More generally, this is used for the pref and should stay in sync with
+  // the code in nsDefaultURIFixup::KeywordURIFixup .
+  if (asciiHost.indexOf('.') == asciiHost.length - 1) {
+    asciiHost = asciiHost.slice(0, -1);
+  }
 
   let onLookupComplete = (request, record, status) => {
     let browser = weakBrowser.get();
     if (!Components.isSuccessCode(status) || !browser)
       return;
 
     let currentURI = browser.currentURI;
     // If we're in case (3) (see above), don't show an info bar.
--- a/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js
+++ b/browser/base/content/test/general/browser_urlbarSearchSingleWordNotification.js
@@ -43,38 +43,43 @@ function* runURLBarSearchTest(valueToOpe
 }
 
 add_task(function* test_navigate_full_domain() {
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   yield* runURLBarSearchTest("www.mozilla.org", false, false);
   gBrowser.removeTab(tab);
 });
 
-add_task(function* test_navigate_single_host() {
-  Services.prefs.setBoolPref("browser.fixup.domainwhitelist.localhost", false);
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-  yield* runURLBarSearchTest("localhost", true, true);
+function get_test_function_for_localhost_with_hostname(hostName) {
+  return function* test_navigate_single_host() {
+    const pref = "browser.fixup.domainwhitelist.localhost";
+    Services.prefs.setBoolPref(pref, false);
+    let tab = gBrowser.selectedTab = gBrowser.addTab();
+    yield* runURLBarSearchTest(hostName, true, true);
 
-  let notificationBox = gBrowser.getNotificationBox(tab.linkedBrowser);
-  let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
-  let docLoadPromise = waitForDocLoadAndStopIt("http://localhost/");
-  notification.querySelector(".notification-button-default").click();
+    let notificationBox = gBrowser.getNotificationBox(tab.linkedBrowser);
+    let notification = notificationBox.getNotificationWithValue("keyword-uri-fixup");
+    let docLoadPromise = waitForDocLoadAndStopIt("http://" + hostName + "/");
+    notification.querySelector(".notification-button-default").click();
 
-  // check pref value
-  let pref = "browser.fixup.domainwhitelist.localhost";
-  let prefValue = Services.prefs.getBoolPref(pref);
-  ok(prefValue, "Pref should have been toggled");
+    // check pref value
+    let prefValue = Services.prefs.getBoolPref(pref);
+    ok(prefValue, "Pref should have been toggled");
+
+    yield docLoadPromise;
+    gBrowser.removeTab(tab);
 
-  yield docLoadPromise;
-  gBrowser.removeTab(tab);
+    // Now try again with the pref set.
+    let tab = gBrowser.selectedTab = gBrowser.addTab();
+    yield* runURLBarSearchTest(hostName, false, false);
+    gBrowser.removeTab(tab);
+  }
+}
 
-  // Now try again with the pref set.
-  let tab = gBrowser.selectedTab = gBrowser.addTab();
-  yield* runURLBarSearchTest("localhost", false, false);
-  gBrowser.removeTab(tab);
-});
+add_task(get_test_function_for_localhost_with_hostname("localhost"));
+add_task(get_test_function_for_localhost_with_hostname("localhost."));
 
 add_task(function* test_navigate_invalid_url() {
   let tab = gBrowser.selectedTab = gBrowser.addTab();
   yield* runURLBarSearchTest("mozilla is awesome", true, false);
   gBrowser.removeTab(tab);
 });
 
--- a/docshell/base/nsDefaultURIFixup.cpp
+++ b/docshell/base/nsDefaultURIFixup.cpp
@@ -180,20 +180,23 @@ nsDefaultURIFixup::GetFixupURIInfo(const
         uri->GetSpec(spec);
         uriString.AssignLiteral("view-source:");
         uriString.Append(spec);
     }
     else {
         // Check for if it is a file URL
         nsCOMPtr<nsIURI> uri;
         FileURIFixup(uriString, getter_AddRefs(uri));
+        // NB: FileURIFixup only returns a URI if it had to fix the protocol to
+        // do so, so passing in file:///foo/bar will not hit this path:
         if (uri)
         {
             uri.swap(info->mFixedURI);
             info->mPreferredURI = info->mFixedURI;
+            info->mFixupChangedProtocol = true;
             return NS_OK;
         }
 
 #if defined(XP_WIN)
         // Not a file URL, so translate '\' to '/' for convenience in the common protocols
         // e.g. catch
         //
         //   http:\\broken.com\address
@@ -240,72 +243,72 @@ nsDefaultURIFixup::GetFixupURIInfo(const
                 "Failed to observe \"browser.fixup.typo.scheme\"");
 
       rv = Preferences::AddBoolVarCache(&sFixupKeywords, "keyword.enabled",
                                         sFixupKeywords);
       MOZ_ASSERT(NS_SUCCEEDED(rv), "Failed to observe \"keyword.enabled\"");
       sInitializedPrefCaches = true;
     }
 
-    info->mInputHasProtocol = !scheme.IsEmpty();
-
     // Fix up common scheme typos.
     if (sFixTypos && (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) {
 
         // Fast-path for common cases.
         if (scheme.IsEmpty() ||
             scheme.LowerCaseEqualsLiteral("http") ||
             scheme.LowerCaseEqualsLiteral("https") ||
             scheme.LowerCaseEqualsLiteral("ftp") ||
             scheme.LowerCaseEqualsLiteral("file")) {
             // Do nothing.
         } else if (scheme.LowerCaseEqualsLiteral("ttp")) {
             // ttp -> http.
             uriString.Replace(0, 3, "http");
             scheme.AssignLiteral("http");
+            info->mFixupChangedProtocol = true;
         } else if (scheme.LowerCaseEqualsLiteral("ttps")) {
             // ttps -> https.
             uriString.Replace(0, 4, "https");
             scheme.AssignLiteral("https");
+            info->mFixupChangedProtocol = true;
         } else if (scheme.LowerCaseEqualsLiteral("tps")) {
             // tps -> https.
             uriString.Replace(0, 3, "https");
             scheme.AssignLiteral("https");
+            info->mFixupChangedProtocol = true;
         } else if (scheme.LowerCaseEqualsLiteral("ps")) {
             // ps -> https.
             uriString.Replace(0, 2, "https");
             scheme.AssignLiteral("https");
+            info->mFixupChangedProtocol = true;
         } else if (scheme.LowerCaseEqualsLiteral("ile")) {
             // ile -> file.
             uriString.Replace(0, 3, "file");
             scheme.AssignLiteral("file");
+            info->mFixupChangedProtocol = true;
         } else if (scheme.LowerCaseEqualsLiteral("le")) {
             // le -> file.
             uriString.Replace(0, 2, "file");
             scheme.AssignLiteral("file");
+            info->mFixupChangedProtocol = true;
         }
     }
 
     // Now we need to check whether "scheme" is something we don't
     // really know about.
     nsCOMPtr<nsIProtocolHandler> ourHandler, extHandler;
     
     ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ourHandler));
     extHandler = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX"default");
 
     nsCOMPtr<nsIURI> uri;
     if (ourHandler != extHandler || !PossiblyHostPortUrl(uriString)) {
         // Just try to create an URL out of it
         rv = NS_NewURI(getter_AddRefs(uri), uriString, nullptr);
         if (NS_SUCCEEDED(rv)) {
             info->mFixedURI = uri;
-            // Figure out whether this had a domain or just a single hostname:
-            nsAutoCString host;
-            uri->GetHost(host);
-            info->mInputHostHasDot = host.FindChar('.') != kNotFound;
         }
 
         if (!uri && rv != NS_ERROR_MALFORMED_URI) {
             return rv;
         }
     }
 
     if (uri && ourHandler == extHandler && sFixupKeywords &&
@@ -328,48 +331,45 @@ nsDefaultURIFixup::GetFixupURIInfo(const
                   info->mFixupUsedKeyword = true;
                 }
             }
         }
     }
     
     if (uri) {
         if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
-            MakeAlternateURI(uri);
+            info->mFixupCreatedAlternateURI = MakeAlternateURI(uri);
         info->mPreferredURI = uri;
         return NS_OK;
     }
 
     // Fix up protocol string before calling KeywordURIFixup, because
     // it cares about the hostname of such URIs:
     nsCOMPtr<nsIURI> uriWithProtocol;
     // NB: this rv gets returned at the end of this method if we never
     // do a keyword fixup after this (because the pref or the flags passed
     // might not let us).
-    rv = FixupURIProtocol(uriString, getter_AddRefs(uriWithProtocol));
+    rv = FixupURIProtocol(uriString, info, getter_AddRefs(uriWithProtocol));
     if (uriWithProtocol) {
         info->mFixedURI = uriWithProtocol;
-        nsAutoCString host;
-        uriWithProtocol->GetHost(host);
-        info->mInputHostHasDot = host.FindChar('.') != kNotFound;
     }
 
     // See if it is a keyword
     // Test whether keywords need to be fixed up
     if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
         KeywordURIFixup(uriString, info, aPostData);
         if (info->mPreferredURI)
             return NS_OK;
     }
 
     // Did the caller want us to try an alternative URI?
     // If so, attempt to fixup http://foo into http://www.foo.com
 
     if (info->mFixedURI && aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI) {
-        MakeAlternateURI(info->mFixedURI);
+        info->mFixupCreatedAlternateURI = MakeAlternateURI(info->mFixedURI);
     }
 
     // If we still haven't been able to construct a valid URI, try to force a
     // keyword match.  This catches search strings with '.' or ':' in them.
     if (info->mFixedURI)
     {
         info->mPreferredURI = info->mFixedURI;
     }
@@ -620,17 +620,17 @@ bool nsDefaultURIFixup::IsLikelyFTP(cons
                 break;
             }
             ++iter;
         }
     }
     return likelyFTP;
 }
 
-nsresult nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI, 
+nsresult nsDefaultURIFixup::FileURIFixup(const nsACString& aStringURI,
                                          nsIURI** aURI)
 {
     nsAutoCString uriSpecOut;
 
     nsresult rv = ConvertFileToStringURI(aStringURI, uriSpecOut);
     if (NS_SUCCEEDED(rv))
     {
         // if this is file url, uriSpecOut is already in FS charset
@@ -717,17 +717,18 @@ nsresult nsDefaultURIFixup::ConvertFileT
     }
 
     return NS_ERROR_FAILURE;
 }
 
 
 nsresult
 nsDefaultURIFixup::FixupURIProtocol(const nsACString & aURIString,
-                                         nsIURI** aURI)
+                                    nsDefaultURIFixupInfo* aFixupInfo,
+                                    nsIURI** aURI)
 {
     nsAutoCString uriString(aURIString);
     *aURI = nullptr;
 
     // Prune duff protocol schemes
     //
     //   ://totallybroken.url.com
     //   //shorthand.url.com
@@ -763,16 +764,17 @@ nsDefaultURIFixup::FixupURIProtocol(cons
         nsAutoCString hostSpec;
         uriString.Left(hostSpec, hostPos);
 
         // insert url spec corresponding to host name
         if (IsLikelyFTP(hostSpec))
             uriString.InsertLiteral("ftp://", 0);
         else
             uriString.InsertLiteral("http://", 0);
+        aFixupInfo->mFixupChangedProtocol = true;
     } // end if checkprotocol
 
     return NS_NewURI(aURI, uriString, nullptr);
 }
 
 
 bool nsDefaultURIFixup::PossiblyHostPortUrl(const nsACString &aUrl)
 {
@@ -902,99 +904,115 @@ void nsDefaultURIFixup::KeywordURIFixup(
     // These are keyword formatted strings
     // "what is mozilla"
     // "what is mozilla?"
     // "docshell site:mozilla.org" - has no dot/colon in the first space-separated substring
     // "?mozilla" - anything that begins with a question mark
     // "?site:mozilla.org docshell"
     // Things that have a quote before the first dot/colon
     // "mozilla" - checked against a whitelist to see if it's a host or not
+    // ".mozilla", "mozilla." - ditto
 
     // These are not keyword formatted strings
     // "www.blah.com" - first space-separated substring contains a dot, doesn't start with "?"
     // "www.blah.com stuff"
     // "nonQualifiedHost:80" - first space-separated substring contains a colon, doesn't start with "?"
     // "nonQualifiedHost:80 args"
     // "nonQualifiedHost?"
     // "nonQualifiedHost?args"
     // "nonQualifiedHost?some args"
+    // "blah.com."
 
     // Note: uint32_t(kNotFound) is greater than any actual location
     // in practice.  So if we cast all locations to uint32_t, then a <
     // b guarantees that either b is kNotFound and a is found, or both
     // are found and a found before b.
     uint32_t dotLoc   = uint32_t(aURIString.FindChar('.'));
+    nsAutoCString tmpURIString(aURIString);
+    uint32_t lastDotLoc = uint32_t(tmpURIString.RFindChar('.'));
     uint32_t colonLoc = uint32_t(aURIString.FindChar(':'));
     uint32_t spaceLoc = uint32_t(aURIString.FindChar(' '));
     if (spaceLoc == 0) {
         // Treat this as not found
         spaceLoc = uint32_t(kNotFound);
     }
     uint32_t qMarkLoc = uint32_t(aURIString.FindChar('?'));
     uint32_t quoteLoc = std::min(uint32_t(aURIString.FindChar('"')),
                                uint32_t(aURIString.FindChar('\'')));
 
     nsresult rv;
+    // We do keyword lookups if a space or quote preceded the dot, colon
+    // or question mark (or if the latter were not found):
     if (((spaceLoc < dotLoc || quoteLoc < dotLoc) &&
          (spaceLoc < colonLoc || quoteLoc < colonLoc) &&
          (spaceLoc < qMarkLoc || quoteLoc < qMarkLoc)) ||
         qMarkLoc == 0)
     {
         rv = KeywordToURI(aURIString, aPostData,
                           getter_AddRefs(aFixupInfo->mPreferredURI));
         if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI)
         {
             aFixupInfo->mFixupUsedKeyword = true;
         }
     }
-    else if (dotLoc == uint32_t(kNotFound) && colonLoc == uint32_t(kNotFound) &&
-             qMarkLoc == uint32_t(kNotFound))
+    // ... or if there is no question mark or colon, and there is either no
+    // dot, or exactly 1 and it is the first or last character of the input:
+    else if ((dotLoc == uint32_t(kNotFound) ||
+              (dotLoc == lastDotLoc && (dotLoc == 0 || dotLoc == aURIString.Length() - 1))) &&
+             colonLoc == uint32_t(kNotFound) && qMarkLoc == uint32_t(kNotFound))
     {
         nsAutoCString asciiHost;
         if (NS_SUCCEEDED(aFixupInfo->mFixedURI->GetAsciiHost(asciiHost)) &&
             !asciiHost.IsEmpty())
         {
             // Check if this domain is whitelisted as an actual
             // domain (which will prevent a keyword query)
+            // NB: any processing of the host here should stay in sync with
+            // code in the front-end(s) that set the pref.
             nsAutoCString pref("browser.fixup.domainwhitelist.");
-            pref.Append(asciiHost);
+            if (dotLoc == aURIString.Length() - 1) {
+              pref.Append(Substring(asciiHost, 0, asciiHost.Length() - 1));
+            } else {
+              pref.Append(asciiHost);
+            }
             if (Preferences::GetBool(pref.get(), false))
             {
                 return;
             }
         }
         // If we get here, we don't have a valid URI, or we did but the
         // host is not whitelisted, so we do a keyword search *anyway*:
         rv = KeywordToURI(aURIString, aPostData,
                           getter_AddRefs(aFixupInfo->mPreferredURI));
         if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI)
         {
             aFixupInfo->mFixupUsedKeyword = true;
         }
     }
 }
 
+
 nsresult NS_NewURIFixup(nsIURIFixup **aURIFixup)
 {
     nsDefaultURIFixup *fixup = new nsDefaultURIFixup;
     if (fixup == nullptr)
     {
         return NS_ERROR_OUT_OF_MEMORY;
     }
     return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);
 }
 
 
 /* Implementation of nsIURIFixupInfo */
 NS_IMPL_ISUPPORTS(nsDefaultURIFixupInfo, nsIURIFixupInfo)
 
 nsDefaultURIFixupInfo::nsDefaultURIFixupInfo(const nsACString& aOriginalInput):
     mFixupUsedKeyword(false),
-    mInputHasProtocol(false),
-    mInputHostHasDot(false)
+    mFixupChangedProtocol(false),
+    mFixupCreatedAlternateURI(false)
 {
   mOriginalInput = aOriginalInput;
 }
 
 
 nsDefaultURIFixupInfo::~nsDefaultURIFixupInfo()
 {
 }
@@ -1033,26 +1051,26 @@ nsDefaultURIFixupInfo::GetFixedURI(nsIUR
 NS_IMETHODIMP
 nsDefaultURIFixupInfo::GetFixupUsedKeyword(bool* aOut)
 {
     *aOut = mFixupUsedKeyword;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDefaultURIFixupInfo::GetInputHasProtocol(bool* aOut)
+nsDefaultURIFixupInfo::GetFixupChangedProtocol(bool* aOut)
 {
-    *aOut = mInputHasProtocol;
+    *aOut = mFixupChangedProtocol;
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDefaultURIFixupInfo::GetInputHostHasDot(bool* aOut)
+nsDefaultURIFixupInfo::GetFixupCreatedAlternateURI(bool* aOut)
 {
-    *aOut = mInputHostHasDot;
+    *aOut = mFixupCreatedAlternateURI;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDefaultURIFixupInfo::GetOriginalInput(nsACString& aInput)
 {
     aInput = mOriginalInput;
     return NS_OK;
--- a/docshell/base/nsDefaultURIFixup.h
+++ b/docshell/base/nsDefaultURIFixup.h
@@ -22,17 +22,19 @@ public:
 
 protected:
     virtual ~nsDefaultURIFixup();
 
 private:
     /* additional members */
     nsresult FileURIFixup(const nsACString &aStringURI, nsIURI** aURI);
     nsresult ConvertFileToStringURI(const nsACString& aIn, nsCString& aOut);
-    nsresult FixupURIProtocol(const nsACString& aIn, nsIURI** aURI);
+    nsresult FixupURIProtocol(const nsACString& aIn,
+                              nsDefaultURIFixupInfo* aFixupInfo,
+                              nsIURI** aURI);
     void KeywordURIFixup(const nsACString &aStringURI,
                          nsDefaultURIFixupInfo* aFixupInfo,
                          nsIInputStream** aPostData);
     bool PossiblyByteExpandedFileName(const nsAString& aIn);
     bool PossiblyHostPortUrl(const nsACString& aUrl);
     bool MakeAlternateURI(nsIURI *aURI);
     bool IsLikelyFTP(const nsCString& aHostSpec);
 };
@@ -50,13 +52,13 @@ public:
 protected:
     virtual ~nsDefaultURIFixupInfo();
 
 private:
     nsCOMPtr<nsISupports> mConsumer;
     nsCOMPtr<nsIURI> mPreferredURI;
     nsCOMPtr<nsIURI> mFixedURI;
     bool mFixupUsedKeyword;
-    bool mInputHasProtocol;
-    bool mInputHostHasDot;
+    bool mFixupChangedProtocol;
+    bool mFixupCreatedAlternateURI;
     nsAutoCString mOriginalInput;
 };
 #endif
--- a/docshell/base/nsIURIFixup.idl
+++ b/docshell/base/nsIURIFixup.idl
@@ -7,17 +7,17 @@
 #include "nsISupports.idl"
 
 interface nsIURI;
 interface nsIInputStream;
 
 /**
  * Interface indicating what we found/corrected when fixing up a URI
  */
-[scriptable, uuid(c9b6cc32-c24e-4283-adaa-9290577fd609)]
+[scriptable, uuid(62aac1e0-3da8-4920-bd1b-a54fc2e2eb24)]
 interface nsIURIFixupInfo : nsISupports
 {
   /**
    * Consumer that asked for fixed up URI.
    */
   attribute nsISupports consumer;
 
   /**
@@ -36,27 +36,27 @@ interface nsIURIFixupInfo : nsISupports
   readonly attribute nsIURI fixedURI;
 
   /**
    * Whether the preferred option ended up using a keyword search.
    */
   readonly attribute boolean fixupUsedKeyword;
 
   /**
-   * Whether we think there was a protocol specified in some way,
-   * even if we corrected it (e.g. "ttp://foo.com/bar")
+   * Whether we changed the protocol instead of using one from the input as-is.
    */
-  readonly attribute boolean inputHasProtocol;
+  readonly attribute boolean fixupChangedProtocol;
 
   /**
-   * Whether the input included a dot in the hostname, e.g. "mozilla.org"
-   * rather than just "mozilla". This makes a difference in terms of when we
-   * decide to do a keyword search or not.
+   * Whether we created an alternative URI. We might have added a prefix and/or
+   * suffix, the contents of which are controlled by the
+   * browser.fixup.alternate.prefix and .suffix prefs, with the defaults being
+   * "www." and ".com", respectively.
    */
-  readonly attribute boolean inputHostHasDot;
+  readonly attribute boolean fixupCreatedAlternateURI;
 
   /**
    * The original input
    */
   readonly attribute AUTF8String originalInput;
 };
 
 
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -40,108 +40,89 @@ let flagInputs = [
 flagInputs.concat([
   flagInputs[0] | flagInputs[1],
   flagInputs[1] | flagInputs[2],
   flagInputs[0] | flagInputs[2],
   flagInputs[0] | flagInputs[1] | flagInputs[2]
 ]);
 
 let testcases = [
-  ["http://www.mozilla.org", "http://www.mozilla.org/"],
-  ["://www.mozilla.org", "http://www.mozilla.org/"],
-  ["www.mozilla.org", "http://www.mozilla.org/"],
-  ["http://mozilla/", "http://mozilla/"],
-  ["127.0.0.1", "http://127.0.0.1/"],
-  ["1234", "http://1234/"],
-  ["host/foo.txt", "http://host/foo.txt"],
-  ["mozilla", "http://mozilla/"],
-  ["mozilla is amazing", null],
-  ["", null],
+  ["http://www.mozilla.org", "http://www.mozilla.org/", null, false, false],
+  ["http://127.0.0.1/", "http://127.0.0.1/", null, false, false],
+  ["file:///foo/bar", "file:///foo/bar", null, false, false],
+  ["://www.mozilla.org", "http://www.mozilla.org/", null, false, true],
+  ["www.mozilla.org", "http://www.mozilla.org/", null, false, true],
+  ["http://mozilla/", "http://mozilla/", "http://www.mozilla.com/", false, false],
+  ["http://test./", "http://test./", "http://www.test./", false, false],
+  ["127.0.0.1", "http://127.0.0.1/", null, false, true],
+  ["1234", "http://1234/", "http://www.1234.com/", true, true],
+  ["host/foo.txt", "http://host/foo.txt", "http://www.host.com/foo.txt", false, true],
+  ["mozilla", "http://mozilla/", "http://www.mozilla.com/", true, true],
+  ["test.", "http://test./", "http://www.test./", true, true],
+  [".test", "http://.test/", "http://www..test/", true, true],
+  ["mozilla is amazing", null, null, true, true],
+  ["", null, null, true, true]
 ];
 
 if (Services.appinfo.OS.toLowerCase().startsWith("win")) {
-  testcases.push(["C:\\some\\file.txt", "file:///C:/some/file.txt"]);
+  testcases.push(["C:\\some\\file.txt", "file:///C:/some/file.txt", null, false, true]);
 } else {
-  testcases.push(["/some/file.txt", "file:///some/file.txt"]);
+  testcases.push(["/some/file.txt", "file:///some/file.txt", null, false, true]);
 }
 
 function run_test() {
-  for (let [testInput, expectedFixedURI] of testcases) {
+  for (let [testInput, expectedFixedURI, alternativeURI,
+            expectKeywordLookup, expectProtocolChange] of testcases) {
     for (let flags of flagInputs) {
       let info;
       let fixupURIOnly = null;
       try {
         fixupURIOnly = urifixup.createFixupURI(testInput, flags);
       } catch (ex) {
+        do_print("Caught exception: " + ex);
         do_check_eq(expectedFixedURI, null);
       }
 
       try {
         info = urifixup.getFixupURIInfo(testInput, flags);
       } catch (ex) {
         // Both APIs should return an error in the same cases.
+        do_print("Caught exception: " + ex);
         do_check_eq(expectedFixedURI, null);
         do_check_eq(fixupURIOnly, null);
         continue;
       }
 
+      do_print("Checking " + testInput + " with flags " + flags);
+
       // Both APIs should then also be using the same spec.
       do_check_eq(fixupURIOnly.spec, info.preferredURI.spec);
 
       let isFileURL = expectedFixedURI && expectedFixedURI.startsWith("file");
 
       // Check the fixedURI:
-      let alternateURI = flags & urifixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI;
-      if (!isFileURL && alternateURI && !info.inputHostHasDot && info.fixedURI) {
-        let originalURI = Services.io.newURI(expectedFixedURI, null, null);
-        do_check_eq(info.fixedURI.host, "www." + originalURI.host + ".com");
+      let makeAlternativeURI = flags & urifixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI;
+      if (makeAlternativeURI && alternativeURI != null) {
+        do_check_eq(info.fixedURI.spec, alternativeURI);
       } else {
         do_check_eq(info.fixedURI && info.fixedURI.spec, expectedFixedURI);
       }
 
       // Check booleans on input:
-      if (isFileURL) {
-        do_check_eq(info.inputHasProtocol, testInput.startsWith("file:"));
-        do_check_eq(info.inputHostHasDot, false);
+      let couldDoKeywordLookup = flags & urifixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+      do_check_eq(info.fixupUsedKeyword, couldDoKeywordLookup && expectKeywordLookup);
+      do_check_eq(info.fixupChangedProtocol, expectProtocolChange);
+      do_check_eq(info.fixupCreatedAlternateURI, makeAlternativeURI && alternativeURI != null);
+
+      // Check the preferred URI
+      if (couldDoKeywordLookup && expectKeywordLookup) {
+        let urlparamInput = testInput.replace(/ /g, '+');
+        let searchURL = kSearchEngineURL.replace("{searchTerms}", urlparamInput);
+        do_check_eq(info.preferredURI.spec, searchURL);
       } else {
-        // The duff protocol doesn't count, so > 0 rather than -1:
-        do_check_eq(info.inputHasProtocol, testInput.indexOf(":") > 0);
-        let dotIndex = testInput.indexOf(".");
-        let slashIndex = testInput.replace("://", "").indexOf("/");
-        slashIndex = slashIndex == -1 ? testInput.length : slashIndex;
-        do_check_eq(info.inputHostHasDot, dotIndex != -1 && slashIndex > dotIndex);
-      }
-
-      let couldDoKeywordLookup = flags & urifixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
-      // Check the preferred URI
-      if (info.inputHostHasDot || info.inputHasProtocol) {
         // In these cases, we should never be doing a keyword lookup and
         // the fixed URI should be preferred:
         do_check_eq(info.preferredURI.spec, info.fixedURI.spec);
-      } else if (!isFileURL && couldDoKeywordLookup && testInput.indexOf(".") == -1) {
-        // Otherwise, and assuming we're allowed, there will be a search URI:
-        let urlparamInput = testInput.replace(/ /g, '+');
-        let searchURL = kSearchEngineURL.replace("{searchTerms}", urlparamInput);
-        do_check_eq(info.preferredURI.spec, searchURL);
-      } else if (info.fixedURI) {
-        // This is for lack of keyword lookup, combined with hostnames with no
-        // protocol:
-        do_check_eq(info.fixedURI, info.preferredURI);
-        if (isFileURL) {
-          do_check_eq(info.fixedURI.host, "");
-        } else {
-          let hostMatch = testInput.match(/(?:[^:\/]*:\/\/)?([^\/]+)(\/|$)/);
-          let host = hostMatch ? hostMatch[1] : "";
-          if (alternateURI) {
-            do_check_eq(info.fixedURI.host, "www." + host + ".com");
-          } else {
-            do_check_eq(info.fixedURI.host, host);
-          }
-        }
-      } else {
-        do_check_true(false, "There should be no cases where we got here, " +
-                             "there's no keyword lookup, and no fixed URI." +
-                             "Offending input: " + testInput);
       }
       do_check_eq(testInput, info.originalInput);
     }
   }
 }