Bug 1057166 - move FHR reporting out of docshell and fix test to work in e10s, r=bz
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 11 Sep 2014 14:50:55 +0100
changeset 231669 3b0e81a6e214577052544e7480e1325d38bb2dfc
parent 231668 d1ff54346db581bff69c35da6e0a948bbbe609a8
child 231670 5d0c25294add2172193018eb8e8b00623591eeab
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1057166
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1057166 - move FHR reporting out of docshell and fix test to work in e10s, r=bz
browser/base/content/browser.js
docshell/base/nsDefaultURIFixup.cpp
docshell/base/nsDefaultURIFixup.h
docshell/base/nsDocShell.cpp
docshell/base/nsDocShell.h
docshell/base/nsIURIFixup.idl
docshell/test/browser/browser.ini
docshell/test/browser/browser_search_notification.js
docshell/test/unit/test_nsDefaultURIFixup_info.js
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/ipc/moz.build
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -689,17 +689,17 @@ var gPopupBlockerObserver = {
 
 function gKeywordURIFixup({ target: browser, data: fixupInfo }) {
   let deserializeURI = (spec) => spec ? makeURI(spec) : null;
 
   // We get called irrespective of whether we did a keyword search, or
   // whether the original input would be vaguely interpretable as a URL,
   // so figure that out first.
   let alternativeURI = deserializeURI(fixupInfo.fixedURI);
-  if (!fixupInfo.fixupUsedKeyword || !alternativeURI || !alternativeURI.host) {
+  if (!fixupInfo.keywordProviderName  || !alternativeURI || !alternativeURI.host) {
     return;
   }
 
   // At this point we're still only just about to load this URI.
   // When the async DNS lookup comes back, we may be in any of these states:
   // 1) still on the previous URI, waiting for the preferredURI (keyword
   //    search) to respond;
   // 2) at the keyword search URI (preferredURI)
--- a/docshell/base/nsDefaultURIFixup.cpp
+++ b/docshell/base/nsDefaultURIFixup.cpp
@@ -295,56 +295,51 @@ nsDefaultURIFixup::GetFixupURIInfo(const
 
     // 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;
-        }
+        rv = NS_NewURI(getter_AddRefs(info->mFixedURI), uriString, nullptr);
 
-        if (!uri && rv != NS_ERROR_MALFORMED_URI) {
+        if (!info->mFixedURI && rv != NS_ERROR_MALFORMED_URI) {
             return rv;
         }
     }
 
-    if (uri && ourHandler == extHandler && sFixupKeywords &&
+    if (info->mFixedURI && ourHandler == extHandler && sFixupKeywords &&
         (aFixupFlags & FIXUP_FLAG_FIX_SCHEME_TYPOS)) {
         nsCOMPtr<nsIExternalProtocolService> extProtService =
             do_GetService(NS_EXTERNALPROTOCOLSERVICE_CONTRACTID);
         if (extProtService) {
             bool handlerExists = false;
             rv = extProtService->ExternalProtocolHandlerExists(scheme.get(), &handlerExists);
             if (NS_FAILED(rv)) {
                 return rv;
             }
             // This basically means we're dealing with a theoretically valid
             // URI... but we have no idea how to load it. (e.g. "christmas:humbug")
             // It's more likely the user wants to search, and so we
             // chuck this over to their preferred search provider instead:
             if (!handlerExists) {
-                nsresult rv = KeywordToURI(uriString, aPostData, getter_AddRefs(uri));
-                if (NS_SUCCEEDED(rv) && uri) {
-                  info->mFixupUsedKeyword = true;
-                }
+                TryKeywordFixupForURIInfo(uriString, info, aPostData);
             }
         }
     }
     
-    if (uri) {
-        if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
-            info->mFixupCreatedAlternateURI = MakeAlternateURI(uri);
-        info->mPreferredURI = uri;
+    if (info->mFixedURI) {
+        if (!info->mPreferredURI) {
+            if (aFixupFlags & FIXUP_FLAGS_MAKE_ALTERNATE_URI)
+                info->mFixupCreatedAlternateURI = MakeAlternateURI(info->mFixedURI);
+            info->mPreferredURI = info->mFixedURI;
+        }
         return NS_OK;
     }
 
     // Fix up protocol string before calling KeywordURIFixup, because
     // it cares about the hostname of such URIs:
     nsCOMPtr<nsIURI> uriWithProtocol;
     bool inputHadDuffProtocol = false;
 
@@ -369,19 +364,20 @@ nsDefaultURIFixup::GetFixupURIInfo(const
     if (uriWithProtocol) {
         info->mFixedURI = uriWithProtocol;
     }
 
     // See if it is a keyword
     // Test whether keywords need to be fixed up
     if (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) &&
         !inputHadDuffProtocol) {
-        KeywordURIFixup(uriString, info, aPostData);
-        if (info->mPreferredURI)
+        if (NS_SUCCEEDED(KeywordURIFixup(uriString, info, aPostData)) &&
+            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) {
         info->mFixupCreatedAlternateURI = MakeAlternateURI(info->mFixedURI);
     }
@@ -410,32 +406,29 @@ nsDefaultURIFixup::GetFixupURIInfo(const
         }
 
         return NS_OK;
     }
 
     // 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 (sFixupKeywords && (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
-        rv = KeywordToURI(aStringURI, aPostData, getter_AddRefs(info->mPreferredURI));
-        if (NS_SUCCEEDED(rv) && info->mPreferredURI)
-        {
-            info->mFixupUsedKeyword = true;
-            return NS_OK;
-        }
+        rv = TryKeywordFixupForURIInfo(aStringURI, info, aPostData);
     }
 
     return rv;
 }
 
 NS_IMETHODIMP nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
                                               nsIInputStream **aPostData,
-                                              nsIURI **aURI)
+                                              nsIURIFixupInfo **aInfo)
 {
-    *aURI = nullptr;
+    nsRefPtr<nsDefaultURIFixupInfo> info = new nsDefaultURIFixupInfo(aKeyword);
+    NS_ADDREF(*aInfo = info);
+
     if (aPostData) {
         *aPostData = nullptr;
     }
     NS_ENSURE_STATE(Preferences::GetRootBranch());
 
     // Strip leading "?" and leading/trailing spaces from aKeyword
     nsAutoCString keyword(aKeyword);
     if (StringBeginsWith(keyword, NS_LITERAL_CSTRING("?"))) {
@@ -446,30 +439,34 @@ NS_IMETHODIMP nsDefaultURIFixup::Keyword
     if (XRE_GetProcessType() == GeckoProcessType_Content) {
         dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
         if (!contentChild) {
             return NS_ERROR_NOT_AVAILABLE;
         }
 
         ipc::OptionalInputStreamParams postData;
         ipc::OptionalURIParams uri;
-        if (!contentChild->SendKeywordToURI(keyword, &postData, &uri)) {
+        nsAutoString providerName;
+        if (!contentChild->SendKeywordToURI(keyword, &providerName, &postData, &uri)) {
             return NS_ERROR_FAILURE;
         }
 
+        CopyUTF8toUTF16(keyword, info->mKeywordAsSent);
+        info->mKeywordProviderName = providerName;
+
         if (aPostData) {
             nsTArray<ipc::FileDescriptor> fds;
             nsCOMPtr<nsIInputStream> temp = DeserializeInputStream(postData, fds);
             temp.forget(aPostData);
 
             MOZ_ASSERT(fds.IsEmpty());
         }
 
         nsCOMPtr<nsIURI> temp = DeserializeURI(uri);
-        temp.forget(aURI);
+        info->mPreferredURI = temp.forget();
         return NS_OK;
     }
 
 #ifdef MOZ_TOOLKIT_SEARCH
     // Try falling back to the search service's default search engine
     nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1");
     if (searchSvc) {
         nsCOMPtr<nsISearchEngine> defaultEngine;
@@ -481,17 +478,18 @@ NS_IMETHODIMP nsDefaultURIFixup::Keyword
             // parameters that are specific to keyword searches.
             NS_NAMED_LITERAL_STRING(mozKeywordSearch, "application/x-moz-keywordsearch");
             bool supportsResponseType = false;
             defaultEngine->SupportsResponseType(mozKeywordSearch, &supportsResponseType);
             if (supportsResponseType) {
                 responseType.Assign(mozKeywordSearch);
             }
 
-            defaultEngine->GetSubmission(NS_ConvertUTF8toUTF16(keyword),
+            NS_ConvertUTF8toUTF16 keywordW(keyword);
+            defaultEngine->GetSubmission(keywordW,
                                          responseType,
                                          NS_LITERAL_STRING("keyword"),
                                          getter_AddRefs(submission));
 
             if (submission) {
                 nsCOMPtr<nsIInputStream> postData;
                 submission->GetPostData(getter_AddRefs(postData));
                 if (aPostData) {
@@ -499,40 +497,44 @@ NS_IMETHODIMP nsDefaultURIFixup::Keyword
                 } else if (postData) {
                   // The submission specifies POST data (i.e. the search
                   // engine's "method" is POST), but our caller didn't allow
                   // passing post data back. No point passing back a URL that
                   // won't load properly.
                   return NS_ERROR_FAILURE;
                 }
 
-                // This notification is meant for Firefox Health Report so it
-                // can increment counts from the search engine. The assumption
-                // here is that this keyword/submission will eventually result
-                // in a search. Since we only generate a URI here, there is the
-                // possibility we'll increment the counter without actually
-                // incurring a search. A robust solution would involve currying
-                // the search engine's name through various function calls.
-                nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
-                if (obsSvc) {
-                  // Note that "keyword-search" refers to a search via the url
-                  // bar, not a bookmarks keyword search.
-                  obsSvc->NotifyObservers(defaultEngine, "keyword-search", NS_ConvertUTF8toUTF16(keyword).get());
-                }
-
-                return submission->GetUri(aURI);
+                defaultEngine->GetName(info->mKeywordProviderName);
+                info->mKeywordAsSent = keywordW;
+                return submission->GetUri(getter_AddRefs(info->mPreferredURI));
             }
         }
     }
 #endif
 
     // out of options
     return NS_ERROR_NOT_AVAILABLE;
 }
 
+// Helper to deal with passing around uri fixup stuff
+nsresult
+nsDefaultURIFixup::TryKeywordFixupForURIInfo(const nsACString & aURIString,
+                                             nsDefaultURIFixupInfo* aFixupInfo,
+                                             nsIInputStream **aPostData)
+{
+    nsCOMPtr<nsIURIFixupInfo> keywordInfo;
+    nsresult rv = KeywordToURI(aURIString, aPostData, getter_AddRefs(keywordInfo));
+    if (NS_SUCCEEDED(rv)) {
+        keywordInfo->GetKeywordProviderName(aFixupInfo->mKeywordProviderName);
+        keywordInfo->GetKeywordAsSent(aFixupInfo->mKeywordAsSent);
+        keywordInfo->GetPreferredURI(getter_AddRefs(aFixupInfo->mPreferredURI));
+    }
+    return rv;
+}
+
 bool nsDefaultURIFixup::MakeAlternateURI(nsIURI *aURI)
 {
     if (!Preferences::GetRootBranch())
     {
         return false;
     }
     if (!Preferences::GetBool("browser.fixup.alternate.enabled", true))
     {
@@ -918,19 +920,20 @@ bool nsDefaultURIFixup::PossiblyByteExpa
     {
         if (*iter >= 0x0080 && *iter <= 0x00FF)
             return true;
         ++iter;
     }
     return false;
 }
 
-void nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
-                                        nsDefaultURIFixupInfo* aFixupInfo,
-                                        nsIInputStream **aPostData)
+nsresult
+nsDefaultURIFixup::KeywordURIFixup(const nsACString & aURIString,
+                                   nsDefaultURIFixupInfo* aFixupInfo,
+                                   nsIInputStream **aPostData)
 {
     // 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
@@ -1018,17 +1021,16 @@ void nsDefaultURIFixup::KeywordURIFixup(
         pos++;
         iter++;
     }
 
     if (lastLSBracketLoc > 0 || foundRSBrackets != 1) {
         looksLikeIpv6 = false;
     }
 
-    nsresult rv;
     nsAutoCString asciiHost;
     nsAutoCString host;
 
     bool isValidAsciiHost = aFixupInfo->mFixedURI &&
         NS_SUCCEEDED(aFixupInfo->mFixedURI->GetAsciiHost(asciiHost)) &&
         !asciiHost.IsEmpty();
 
     bool isValidHost = aFixupInfo->mFixedURI &&
@@ -1036,72 +1038,66 @@ void nsDefaultURIFixup::KeywordURIFixup(
         !host.IsEmpty();
 
     // If there are 2 dots and only numbers between them, an optional port number
     // and a trailing slash, then don't do a keyword lookup
     if (foundDots == 2 && lastSlashLoc == pos - 1 &&
         ((foundDots + foundDigits == pos - 1) ||
          (foundColons == 1 && firstColonLoc > lastDotLoc &&
           foundDots + foundDigits + foundColons == pos - 1))) {
-        return;
+        return NS_OK;
     }
 
     uint32_t posWithNoTrailingSlash = pos;
     if (lastSlashLoc == pos - 1) {
         posWithNoTrailingSlash -= 1;
     }
     // If there are 3 dots and only numbers between them, an optional port number
     // and an optional trailling slash, then don't do a keyword lookup (ipv4)
     if (foundDots == 3 &&
         ((foundDots + foundDigits == posWithNoTrailingSlash) ||
          (foundColons == 1 && firstColonLoc > lastDotLoc &&
           foundDots + foundDigits + foundColons == posWithNoTrailingSlash))) {
-        return;
+        return NS_OK;
     }
 
     // If there are only colons and only hexadecimal characters ([a-z][0-9])
     // enclosed in [], then don't do a keyword lookup
     if (looksLikeIpv6) {
-        return;
+        return NS_OK;
     }
 
+    nsresult rv = NS_OK;
     // We do keyword lookups if a space or quote preceded the dot, colon
     // or question mark (or if the latter were not found)
     // or when the host is the same as asciiHost and there are no
     // characters from [a-z][A-Z]
     if (((firstSpaceLoc < firstDotLoc || firstQuoteLoc < firstDotLoc) &&
          (firstSpaceLoc < firstColonLoc || firstQuoteLoc < firstColonLoc) &&
          (firstSpaceLoc < firstQMarkLoc || firstQuoteLoc < firstQMarkLoc)) || firstQMarkLoc == 0 ||
         (isValidAsciiHost && isValidHost && !hasAsciiAlpha &&
          host.EqualsIgnoreCase(asciiHost.get()))) {
 
-        rv = KeywordToURI(aFixupInfo->mOriginalInput, aPostData,
-                          getter_AddRefs(aFixupInfo->mPreferredURI));
-        if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI) {
-            aFixupInfo->mFixupUsedKeyword = true;
-        }
+        rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, aPostData);
     }
     // ... 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 ((firstDotLoc == uint32_t(kNotFound) ||
               (foundDots == 1 && (firstDotLoc == 0 || firstDotLoc == aURIString.Length() - 1))) &&
               firstColonLoc == uint32_t(kNotFound) && firstQMarkLoc == uint32_t(kNotFound)) {
 
         if (isValidAsciiHost && IsDomainWhitelisted(asciiHost, firstDotLoc)) {
-            return;
+            return NS_OK;
         }
 
         // 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(aFixupInfo->mOriginalInput, aPostData,
-                          getter_AddRefs(aFixupInfo->mPreferredURI));
-        if (NS_SUCCEEDED(rv) && aFixupInfo->mPreferredURI) {
-            aFixupInfo->mFixupUsedKeyword = true;
-        }
+        rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo, aPostData);
     }
+    return rv;
 }
 
 bool nsDefaultURIFixup::IsDomainWhitelisted(const nsAutoCString aAsciiHost,
                                             const uint32_t aDotLoc)
 {
     // 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
@@ -1129,17 +1125,16 @@ nsresult NS_NewURIFixup(nsIURIFixup **aU
     return fixup->QueryInterface(NS_GET_IID(nsIURIFixup), (void **) aURIFixup);
 }
 
 
 /* Implementation of nsIURIFixupInfo */
 NS_IMPL_ISUPPORTS(nsDefaultURIFixupInfo, nsIURIFixupInfo)
 
 nsDefaultURIFixupInfo::nsDefaultURIFixupInfo(const nsACString& aOriginalInput):
-    mFixupUsedKeyword(false),
     mFixupChangedProtocol(false),
     mFixupCreatedAlternateURI(false)
 {
   mOriginalInput = aOriginalInput;
 }
 
 
 nsDefaultURIFixupInfo::~nsDefaultURIFixupInfo()
@@ -1173,19 +1168,26 @@ NS_IMETHODIMP
 nsDefaultURIFixupInfo::GetFixedURI(nsIURI** aFixedURI)
 {
     *aFixedURI = mFixedURI;
     NS_IF_ADDREF(*aFixedURI);
     return NS_OK;
 }
 
 NS_IMETHODIMP
-nsDefaultURIFixupInfo::GetFixupUsedKeyword(bool* aOut)
+nsDefaultURIFixupInfo::GetKeywordProviderName(nsAString& aOut)
 {
-    *aOut = mFixupUsedKeyword;
+    aOut = mKeywordProviderName;
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsDefaultURIFixupInfo::GetKeywordAsSent(nsAString& aOut)
+{
+    aOut = mKeywordAsSent;
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDefaultURIFixupInfo::GetFixupChangedProtocol(bool* aOut)
 {
     *aOut = mFixupChangedProtocol;
     return NS_OK;
--- a/docshell/base/nsDefaultURIFixup.h
+++ b/docshell/base/nsDefaultURIFixup.h
@@ -25,19 +25,22 @@ protected:
 
 private:
     /* additional members */
     nsresult FileURIFixup(const nsACString &aStringURI, nsIURI** aURI);
     nsresult ConvertFileToStringURI(const nsACString& aIn, nsCString& aOut);
     nsresult FixupURIProtocol(const nsACString& aIn,
                               nsDefaultURIFixupInfo* aFixupInfo,
                               nsIURI** aURI);
-    void KeywordURIFixup(const nsACString &aStringURI,
-                         nsDefaultURIFixupInfo* aFixupInfo,
-                         nsIInputStream** aPostData);
+    nsresult KeywordURIFixup(const nsACString &aStringURI,
+                             nsDefaultURIFixupInfo* aFixupInfo,
+                             nsIInputStream** aPostData);
+    nsresult TryKeywordFixupForURIInfo(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);
     bool IsDomainWhitelisted(const nsAutoCString aAsciiHost,
                              const uint32_t aDotLoc);
 };
 
@@ -53,14 +56,15 @@ public:
 
 protected:
     virtual ~nsDefaultURIFixupInfo();
 
 private:
     nsCOMPtr<nsISupports> mConsumer;
     nsCOMPtr<nsIURI> mPreferredURI;
     nsCOMPtr<nsIURI> mFixedURI;
-    bool mFixupUsedKeyword;
     bool mFixupChangedProtocol;
     bool mFixupCreatedAlternateURI;
+    nsString mKeywordProviderName;
+    nsString mKeywordAsSent;
     nsAutoCString mOriginalInput;
 };
 #endif
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -196,16 +196,20 @@
 #include "nsIURIFixup.h"
 #include "nsIURILoader.h"
 #include "nsIWebBrowserFind.h"
 #include "nsIWidget.h"
 #include "mozilla/dom/EncodingUtils.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/URLSearchParams.h"
 
+#ifdef MOZ_TOOLKIT_SEARCH
+#include "nsIBrowserSearchService.h"
+#endif
+
 static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 //#define DEBUG_DOCSHELL_FOCUS
 #define DEBUG_PAGE_CACHE
 #endif
 
 #ifdef XP_WIN
@@ -4578,41 +4582,41 @@ nsDocShell::LoadURIWithBase(const char16
     uriString.StripChars("\r\n");
     NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
 
     rv = NS_NewURI(getter_AddRefs(uri), uriString);
     if (uri) {
         aLoadFlags &= ~LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP;
     }
     
+    nsCOMPtr<nsIURIFixupInfo> fixupInfo;
     if (sURIFixup) {
         // Call the fixup object.  This will clobber the rv from NS_NewURI
         // above, but that's fine with us.  Note that we need to do this even
         // if NS_NewURI returned a URI, because fixup handles nested URIs, etc
         // (things like view-source:mozilla.org for example).
         uint32_t fixupFlags = 0;
         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
           fixupFlags |= nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
         }
         if (aLoadFlags & LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
           fixupFlags |= nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS;
         }
         nsCOMPtr<nsIInputStream> fixupStream;
-        nsCOMPtr<nsIURIFixupInfo> fixupInfo;
         rv = sURIFixup->GetFixupURIInfo(uriString, fixupFlags,
                                         getter_AddRefs(fixupStream),
                                         getter_AddRefs(fixupInfo));
 
         if (NS_SUCCEEDED(rv)) {
             fixupInfo->GetPreferredURI(getter_AddRefs(uri));
             fixupInfo->SetConsumer(GetAsSupports(this));
         }
 
         if (fixupStream) {
-            // CreateFixupURI only returns a post data stream if it succeeded
+            // GetFixupURIInfo only returns a post data stream if it succeeded
             // and changed the URI, in which case we should override the
             // passed-in post data.
             postStream = fixupStream;
         }
 
         if (aLoadFlags & LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
             nsCOMPtr<nsIObserverService> serv = services::GetObserverService();
             if (serv) {
@@ -4661,16 +4665,23 @@ nsDocShell::LoadURIWithBase(const char16
     }
 
     loadInfo->SetLoadType(ConvertLoadTypeToDocShellLoadInfo(loadType));
     loadInfo->SetPostDataStream(postStream);
     loadInfo->SetReferrer(aReferringURI);
     loadInfo->SetHeadersStream(aHeaderStream);
     loadInfo->SetBaseURI(aBaseURI);
 
+    if (fixupInfo) {
+        nsAutoString searchProvider, keyword;
+        fixupInfo->GetKeywordProviderName(searchProvider);
+        fixupInfo->GetKeywordAsSent(keyword);
+        MaybeNotifyKeywordSearchLoading(searchProvider, keyword);
+    }
+
     rv = LoadURI(uri, loadInfo, extraFlags, true);
 
     // Save URI string in case it's needed later when
     // sending to search engine service in EndPageLoad()
     mOriginalUriString = uriString; 
 
     return rv;
 }
@@ -7377,16 +7388,17 @@ nsDocShell::EndPageLoad(nsIWebProgress *
             nsCOMPtr<nsIInputStream> newPostData;
 
             nsAutoCString oldSpec;
             url->GetSpec(oldSpec);
       
             //
             // First try keyword fixup
             //
+            nsAutoString keywordProviderName, keywordAsSent;
             if (aStatus == NS_ERROR_UNKNOWN_HOST && mAllowKeywordFixup) {
                 bool keywordsEnabled =
                     Preferences::GetBool("keyword.enabled", false);
 
                 nsAutoCString host;
                 url->GetHost(host);
 
                 nsAutoCString scheme;
@@ -7407,21 +7419,22 @@ nsDocShell::EndPageLoad(nsIWebProgress *
                 // determine on a per url basis if we want keywords
                 // enabled...this is just a bandaid...
                 if (keywordsEnabled && !scheme.IsEmpty() &&
                     (scheme.Find("http") != 0)) {
                     keywordsEnabled = false;
                 }
 
                 if (keywordsEnabled && (kNotFound == dotLoc)) {
+                    nsCOMPtr<nsIURIFixupInfo> info;
                     // only send non-qualified hosts to the keyword server
                     if (!mOriginalUriString.IsEmpty()) {
                         sURIFixup->KeywordToURI(mOriginalUriString,
                                                 getter_AddRefs(newPostData),
-                                                getter_AddRefs(newURI));
+                                                getter_AddRefs(info));
                     }
                     else {
                         //
                         // If this string was passed through nsStandardURL by
                         // chance, then it may have been converted from UTF-8 to
                         // ACE, which would result in a completely bogus keyword
                         // query.  Here we try to recover the original Unicode
                         // value, but this is not 100% correct since the value may
@@ -7433,23 +7446,29 @@ nsDocShell::EndPageLoad(nsIWebProgress *
                         nsAutoCString utf8Host;
                         nsCOMPtr<nsIIDNService> idnSrv =
                             do_GetService(NS_IDNSERVICE_CONTRACTID);
                         if (idnSrv &&
                             NS_SUCCEEDED(idnSrv->IsACE(host, &isACE)) && isACE &&
                             NS_SUCCEEDED(idnSrv->ConvertACEtoUTF8(host, utf8Host))) {
                             sURIFixup->KeywordToURI(utf8Host,
                                                     getter_AddRefs(newPostData),
-                                                    getter_AddRefs(newURI));
+                                                    getter_AddRefs(info));
                         } else {
                             sURIFixup->KeywordToURI(host,
                                                     getter_AddRefs(newPostData),
-                                                    getter_AddRefs(newURI));
+                                                    getter_AddRefs(info));
                         }
                     }
+
+                    info->GetPreferredURI(getter_AddRefs(newURI));
+                    if (newURI) {
+                        info->GetKeywordAsSent(keywordAsSent);
+                        info->GetKeywordProviderName(keywordProviderName);
+                    }
                 } // end keywordsEnabled
             }
 
             //
             // Now try change the address, e.g. turn http://foo into
             // http://www.foo.com
             //
             if (aStatus == NS_ERROR_UNKNOWN_HOST ||
@@ -7472,16 +7491,18 @@ nsDocShell::EndPageLoad(nsIWebProgress *
                             // an alternate one.
                             doCreateAlternate = false;
                         }
                     }
                 }
                 if (doCreateAlternate) {
                     newURI = nullptr;
                     newPostData = nullptr;
+                    keywordProviderName.Truncate();
+                    keywordAsSent.Truncate();
                     sURIFixup->CreateFixupURI(oldSpec,
                       nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
                                               getter_AddRefs(newPostData),
                                               getter_AddRefs(newURI));
                 }
             }
 
             // Did we make a new URI that is different to the old one? If so
@@ -7492,16 +7513,20 @@ nsDocShell::EndPageLoad(nsIWebProgress *
                 // otherwise there's little point trying to load it again.
                 bool sameURI = false;
                 url->Equals(newURI, &sameURI);
                 if (!sameURI) {
                     nsAutoCString newSpec;
                     newURI->GetSpec(newSpec);
                     NS_ConvertUTF8toUTF16 newSpecW(newSpec);
 
+                    // This notification is meant for Firefox Health Report so it
+                    // can increment counts from the search engine
+                    MaybeNotifyKeywordSearchLoading(keywordProviderName, keywordAsSent);
+
                     return LoadURI(newSpecW.get(),  // URI string
                                    LOAD_FLAGS_NONE, // Load flags
                                    nullptr,          // Referring URI
                                    newPostData,      // Post data stream
                                    nullptr);         // Headers stream
                 }
             }
         }
@@ -13503,8 +13528,41 @@ nsDocShell::GetOpenedRemote()
   return openedRemote;
 }
 
 URLSearchParams*
 nsDocShell::GetURLSearchParams()
 {
   return mURLSearchParams;
 }
+
+void
+nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString &aProvider,
+                                            const nsString &aKeyword) {
+
+  if (aProvider.IsEmpty()) {
+    return;
+  }
+
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
+    if (contentChild) {
+      contentChild->SendNotifyKeywordSearchLoading(aProvider, aKeyword);
+    }
+    return;
+  }
+
+#ifdef MOZ_TOOLKIT_SEARCH
+  nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1");
+  if (searchSvc) {
+    nsCOMPtr<nsISearchEngine> searchEngine;
+    searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
+    if (searchEngine) {
+      nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+      if (obsSvc) {
+        // Note that "keyword-search" refers to a search via the url
+        // bar, not a bookmarks keyword search.
+        obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
+      }
+    }
+  }
+#endif
+}
--- a/docshell/base/nsDocShell.h
+++ b/docshell/base/nsDocShell.h
@@ -973,16 +973,19 @@ private:
 
     // Separate function to do the actual name (i.e. not _top, _self etc.)
     // searching for FindItemWithName.
     nsresult DoFindItemWithName(const char16_t* aName,
                                 nsISupports* aRequestor,
                                 nsIDocShellTreeItem* aOriginalRequestor,
                                 nsIDocShellTreeItem** _retval);
 
+    // Notify consumers of a search being loaded through the observer service:
+    void MaybeNotifyKeywordSearchLoading(const nsString &aProvider, const nsString &aKeyword);
+
 #ifdef DEBUG
     // We're counting the number of |nsDocShells| to help find leaks
     static unsigned long gNumberOfDocShells;
 #endif /* DEBUG */
 
 public:
     class InterfaceRequestorProxy : public nsIInterfaceRequestor {
     public:
--- 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(62aac1e0-3da8-4920-bd1b-a54fc2e2eb24)]
+[scriptable, uuid(4819f183-b532-4932-ac09-b309cd853be7)]
 interface nsIURIFixupInfo : nsISupports
 {
   /**
    * Consumer that asked for fixed up URI.
    */
   attribute nsISupports consumer;
 
   /**
@@ -31,19 +31,26 @@ interface nsIURIFixupInfo : nsISupports
   /**
    * The fixed-up original input, *never* using a keyword search.
    * (might be null if the original input was not recoverable as
    * a URL, e.g. "foo bar"!)
    */
   readonly attribute nsIURI fixedURI;
 
   /**
-   * Whether the preferred option ended up using a keyword search.
+   * The name of the keyword search provider used to provide a keyword search;
+   * empty string if no keyword search was done.
    */
-  readonly attribute boolean fixupUsedKeyword;
+  readonly attribute AString keywordProviderName;
+
+  /**
+   * The keyword as used for the search (post trimming etc.)
+   * empty string if no keyword search was done.
+   */
+  readonly attribute AString keywordAsSent;
 
   /**
    * Whether we changed the protocol instead of using one from the input as-is.
    */
   readonly attribute boolean fixupChangedProtocol;
 
   /**
    * Whether we created an alternative URI. We might have added a prefix and/or
@@ -58,17 +65,17 @@ interface nsIURIFixupInfo : nsISupports
    */
   readonly attribute AUTF8String originalInput;
 };
 
 
 /**
  * Interface implemented by objects capable of fixing up strings into URIs
  */
-[scriptable, uuid(49298f2b-3630-4874-aecc-522300a7fead)]
+[scriptable, uuid(d2a78abe-e678-4103-9bcc-dd1377460c44)]
 interface nsIURIFixup : nsISupports
 {
     /** No fixup flags. */
     const unsigned long FIXUP_FLAG_NONE = 0;
 
     /**
      * Allow the fixup to use a keyword lookup service to complete the URI.
      * The fixup object implementer should honour this flag and only perform
@@ -141,12 +148,12 @@ interface nsIURIFixup : nsISupports
      *
      * @param aKeyword  The keyword string to convert into a URI
      * @param aPostData The POST data to submit to the returned URI
      *                  (see nsISearchSubmission).
      *
      * @throws NS_ERROR_FAILURE if the resulting URI requires submission of POST
      *         data and aPostData is null.
      */
-    nsIURI keywordToURI(in AUTF8String aKeyword,
-                        [optional] out nsIInputStream aPostData);
+    nsIURIFixupInfo keywordToURI(in AUTF8String aKeyword,
+                                 [optional] out nsIInputStream aPostData);
 };
 
--- a/docshell/test/browser/browser.ini
+++ b/docshell/test/browser/browser.ini
@@ -90,12 +90,11 @@ skip-if = e10s # Bug ?????? - event hand
 skip-if = e10s
 [browser_loadDisallowInherit.js]
 skip-if = e10s
 [browser_loadURI.js]
 skip-if = e10s # Bug ?????? - event handler checks event.target is the content document and test e10s-utils doesn't do that.
 [browser_onbeforeunload_navigation.js]
 skip-if = e10s
 [browser_search_notification.js]
-skip-if = e10s
 [browser_timelineMarkers-01.js]
 [browser_timelineMarkers-02.js]
 skip-if = e10s
--- a/docshell/test/browser/browser_search_notification.js
+++ b/docshell/test/browser/browser_search_notification.js
@@ -1,14 +1,35 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 function test() {
   waitForExplicitFinish();
 
+  const kSearchEngineID = "test_urifixup_search_engine";
+  const kSearchEngineURL = "http://localhost/?search={searchTerms}";
+  Services.search.addEngineWithDetails(kSearchEngineID, "", "", "", "get",
+                                       kSearchEngineURL);
+
+  let oldDefaultEngine = Services.search.defaultEngine;
+  Services.search.defaultEngine = Services.search.getEngineByName(kSearchEngineID);
+
+  let selectedName = Services.search.defaultEngine.name;
+  is(selectedName, kSearchEngineID, "Check fake search engine is selected");
+
+  registerCleanupFunction(function() {
+    if (oldDefaultEngine) {
+      Services.search.defaultEngine = oldDefaultEngine;
+    }
+    let engine = Services.search.getEngineByName(kSearchEngineID);
+    if (engine) {
+      Services.search.removeEngine(engine);
+    }
+  });
+
   let tab = gBrowser.addTab();
   gBrowser.selectedTab = tab;
 
   function observer(subject, topic, data) {
     Services.obs.removeObserver(observer, "keyword-search");
     is(topic, "keyword-search", "Got keyword-search notification");
 
     let engine = Services.search.defaultEngine;
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -525,17 +525,17 @@ function run_test() {
       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:
       let couldDoKeywordLookup = flags & urifixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
-      do_check_eq(info.fixupUsedKeyword, couldDoKeywordLookup && expectKeywordLookup);
+      do_check_eq(!!info.keywordProviderName, couldDoKeywordLookup && expectKeywordLookup);
       do_check_eq(info.fixupChangedProtocol, expectProtocolChange);
       do_check_eq(info.fixupCreatedAlternateURI, makeAlternativeURI && alternativeURI != null);
 
       // Check the preferred URI
       let requiresWhitelistedDomain = flags & urifixup.FIXUP_FLAG_REQUIRE_WHITELISTED_HOST;
       if (couldDoKeywordLookup) {
         if (expectKeywordLookup) {
           if (!affectedByWhitelist || (affectedByWhitelist && !inWhitelist)) {
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -180,16 +180,20 @@ using namespace mozilla::system;
 #include "nsIIPCBackgroundChildCreateCallback.h"
 #endif
 
 
 #if defined(MOZ_CONTENT_SANDBOX) && defined(XP_LINUX)
 #include "mozilla/Sandbox.h"
 #endif
 
+#ifdef MOZ_TOOLKIT_SEARCH
+#include "nsIBrowserSearchService.h"
+#endif
+
 static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID);
 static const char* sClipboardTextFlavors[] = { kUnicodeMime };
 
 using base::ChildPrivileges;
 using base::KillProcess;
 using namespace mozilla::dom::bluetooth;
 using namespace mozilla::dom::cellbroadcast;
 using namespace mozilla::dom::devicestorage;
@@ -3800,40 +3804,67 @@ ContentParent::RecvSetFakeVolumeState(co
     return true;
 #else
     NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined");
     return false;
 #endif
 }
 
 bool
-ContentParent::RecvKeywordToURI(const nsCString& aKeyword, OptionalInputStreamParams* aPostData,
+ContentParent::RecvKeywordToURI(const nsCString& aKeyword,
+                                nsString* aProviderName,
+                                OptionalInputStreamParams* aPostData,
                                 OptionalURIParams* aURI)
 {
     nsCOMPtr<nsIURIFixup> fixup = do_GetService(NS_URIFIXUP_CONTRACTID);
     if (!fixup) {
         return true;
     }
 
     nsCOMPtr<nsIInputStream> postData;
-    nsCOMPtr<nsIURI> uri;
+    nsCOMPtr<nsIURIFixupInfo> info;
+
     if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(postData),
-                                      getter_AddRefs(uri)))) {
+                                      getter_AddRefs(info)))) {
         return true;
     }
+    info->GetKeywordProviderName(*aProviderName);
 
     nsTArray<mozilla::ipc::FileDescriptor> fds;
     SerializeInputStream(postData, *aPostData, fds);
     MOZ_ASSERT(fds.IsEmpty());
 
+    nsCOMPtr<nsIURI> uri;
+    info->GetPreferredURI(getter_AddRefs(uri));
     SerializeURI(uri, *aURI);
     return true;
 }
 
 bool
+ContentParent::RecvNotifyKeywordSearchLoading(const nsString &aProvider,
+                                              const nsString &aKeyword) {
+#ifdef MOZ_TOOLKIT_SEARCH
+    nsCOMPtr<nsIBrowserSearchService> searchSvc = do_GetService("@mozilla.org/browser/search-service;1");
+    if (searchSvc) {
+        nsCOMPtr<nsISearchEngine> searchEngine;
+        searchSvc->GetEngineByName(aProvider, getter_AddRefs(searchEngine));
+        if (searchEngine) {
+            nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
+            if (obsSvc) {
+                // Note that "keyword-search" refers to a search via the url
+                // bar, not a bookmarks keyword search.
+                obsSvc->NotifyObservers(searchEngine, "keyword-search", aKeyword.get());
+            }
+        }
+    }
+#endif
+    return true;
+}
+
+bool
 ContentParent::ShouldContinueFromReplyTimeout()
 {
     return false;
 }
 
 bool
 ContentParent::RecvRecordingDeviceEvents(const nsString& aRecordingStatus,
                                          const nsString& aPageURL,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -626,19 +626,24 @@ private:
 
     virtual bool RecvAddNewProcess(const uint32_t& aPid,
                                    const InfallibleTArray<ProtocolFdMapping>& aFds) MOZ_OVERRIDE;
 
     virtual bool RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) MOZ_OVERRIDE;
 
     virtual bool RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState) MOZ_OVERRIDE;
 
-    virtual bool RecvKeywordToURI(const nsCString& aKeyword, OptionalInputStreamParams* aPostData,
+    virtual bool RecvKeywordToURI(const nsCString& aKeyword,
+                                  nsString* aProviderName,
+                                  OptionalInputStreamParams* aPostData,
                                   OptionalURIParams* aURI) MOZ_OVERRIDE;
 
+    virtual bool RecvNotifyKeywordSearchLoading(const nsString &aProvider,
+                                                const nsString &aKeyword) MOZ_OVERRIDE; 
+
     virtual void ProcessingError(Result what) MOZ_OVERRIDE;
 
     virtual bool RecvAllocateLayerTreeId(uint64_t* aId) MOZ_OVERRIDE;
     virtual bool RecvDeallocateLayerTreeId(const uint64_t& aId) MOZ_OVERRIDE;
 
     virtual bool RecvGetGraphicsFeatureStatus(const int32_t& aFeature,
                                               int32_t* aStatus,
                                               bool* aSuccess) MOZ_OVERRIDE;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -665,17 +665,19 @@ parent:
 
     sync AddNewProcess(uint32_t pid, ProtocolFdMapping[] aFds);
 
     // called by the child (test code only) to propagate volume changes to the parent
     async CreateFakeVolume(nsString fsName, nsString mountPoint);
     async SetFakeVolumeState(nsString fsName, int32_t fsState);
 
     sync KeywordToURI(nsCString keyword)
-        returns (OptionalInputStreamParams postData, OptionalURIParams uri);
+        returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);
+
+    sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword);
 
     // Tell the compositor to allocate a layer tree id for nested remote mozbrowsers.
     sync AllocateLayerTreeId()
         returns (uint64_t id);
     async DeallocateLayerTreeId(uint64_t id);
 
     sync SpeakerManagerForceSpeaker(bool aEnable);
 
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -121,16 +121,19 @@ LOCAL_INCLUDES += [
     '/xpcom/threads',
 ]
 
 DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):
     DEFINES['MOZ_ENABLE_FREETYPE'] = True
 
+if CONFIG['MOZ_TOOLKIT_SEARCH']:
+    DEFINES['MOZ_TOOLKIT_SEARCH'] = True
+
 for var in ('MOZ_PERMISSIONS', 'MOZ_CHILD_PERMISSIONS'):
     if CONFIG[var]:
         DEFINES[var] = True
 
 JAR_MANIFESTS += ['jar.mn']
 
 MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest.ini']