Bug 1586681 - Ensure URIFIxup uses the right engine when there's a separate PB engine. r=Standard8,Gijs
authorMarco Bonardo <mbonardo@mozilla.com>
Sat, 12 Oct 2019 12:37:51 +0000
changeset 497361 1411bb191e69e717fe5d2309be5a6e4f69cf7b16
parent 497360 b4e9b21cd886e4d22997ff24abf941d363f5bfb5
child 497362 09f5cd302da54f83b83cff91a13eea73c7914643
push id97835
push usermak77@bonardo.net
push dateSat, 12 Oct 2019 12:48:59 +0000
treeherderautoland@1411bb191e69 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersStandard8, Gijs
bugs1586681
milestone71.0a1
Bug 1586681 - Ensure URIFIxup uses the right engine when there's a separate PB engine. r=Standard8,Gijs Add a new FIXUP_FLAG_PRIVATE_CONTEXT to nsIURIFixup, make it use the default private search engine when it's set. Update consumers to pass the new flag when necessary. Differential Revision: https://phabricator.services.mozilla.com/D48741
browser/components/urlbar/UrlbarInput.jsm
browser/components/urlbar/UrlbarValueFormatter.jsm
browser/fxr/content/fxrui.js
caps/nsScriptSecurityManager.cpp
docshell/base/nsDefaultURIFixup.cpp
docshell/base/nsDefaultURIFixup.h
docshell/base/nsDocShell.cpp
docshell/base/nsIURIFixup.idl
docshell/test/unit/test_nsDefaultURIFixup_info.js
docshell/test/unit/test_nsDefaultURIFixup_search.js
dom/base/ContentAreaDropListener.jsm
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/webbrowserpersist/nsWebBrowserPersist.h
toolkit/components/places/UnifiedComplete.jsm
toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
toolkit/modules/BrowserUtils.jsm
toolkit/modules/E10SUtils.jsm
--- a/browser/components/urlbar/UrlbarInput.jsm
+++ b/browser/components/urlbar/UrlbarInput.jsm
@@ -627,16 +627,19 @@ class UrlbarInput {
           // dns and prompts the user whether they wanted to rather visit that
           // as a host. On a positive answer, it adds to the domains whitelist
           // that we use to make decisions. Because here we are directly asking
           // for a search, bypassing the docshell, we must do it here.
           // See URIFixupChild.jsm and keyword-uri-fixup.
           let flags =
             Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
             Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+          if (PrivateBrowsingUtils.isWindowPrivate(this.window)) {
+            flags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+          }
           // Don't interrupt the load action in case of errors.
           try {
             let fixupInfo = Services.uriFixup.getFixupURIInfo(
               originalUntrimmedValue.trim(),
               flags
             );
             this.window.gKeywordURIFixup({
               target: this.window.gBrowser.selectedBrowser,
--- a/browser/components/urlbar/UrlbarValueFormatter.jsm
+++ b/browser/components/urlbar/UrlbarValueFormatter.jsm
@@ -7,16 +7,17 @@
 var EXPORTED_SYMBOLS = ["UrlbarValueFormatter"];
 
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
 XPCOMUtils.defineLazyModuleGetters(this, {
   AppConstants: "resource://gre/modules/AppConstants.jsm",
+  PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.jsm",
   Services: "resource://gre/modules/Services.jsm",
   UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
   UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
 });
 
 /**
  * Applies URL highlighting and other styling to the text in the urlbar input,
  * depending on the text.
@@ -106,16 +107,19 @@ class UrlbarValueFormatter {
     }
 
     let url = this.inputField.value;
 
     // Get the URL from the fixup service:
     let flags =
       Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
       Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+    if (PrivateBrowsingUtils.isWindowPrivate(this.window)) {
+      flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+    }
     let uriInfo;
     try {
       uriInfo = Services.uriFixup.getFixupURIInfo(url, flags);
     } catch (ex) {}
     // Ignore if we couldn't make a URI out of this, the URI resulted in a search,
     // or the URI has a non-http(s)/ftp protocol.
     if (
       !uriInfo ||
--- a/browser/fxr/content/fxrui.js
+++ b/browser/fxr/content/fxrui.js
@@ -13,16 +13,19 @@ let browser = null;
 let urlInput = null;
 let secureIcon = null;
 let backButton = null;
 let forwardButton = null;
 let refreshButton = null;
 let stopButton = null;
 
 let { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+const { PrivateBrowsingUtils } = ChromeUtils.import(
+  "resource://gre/modules/PrivateBrowsingUtils.jsm"
+);
 
 window.addEventListener(
   "DOMContentLoaded",
   () => {
     urlInput = document.getElementById("eUrlInput");
     secureIcon = document.getElementById("eUrlSecure");
     backButton = document.getElementById("eBack");
     forwardButton = document.getElementById("eForward");
@@ -135,16 +138,19 @@ function setupUrlBar() {
       // Use the URL Fixup Service in case the user wants to search instead
       // of directly navigating to a location.
       await Services.search.init();
 
       let valueToFixUp = urlInput.value;
       let flags =
         Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
         Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+      if (PrivateBrowsingUtils.isWindowPrivate(window)) {
+        flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+      }
 
       let uriToLoad = Services.uriFixup.createFixupURI(valueToFixUp, flags);
 
       browser.loadURI(uriToLoad.spec);
       browser.focus();
     }
   });
 
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -1063,17 +1063,21 @@ nsScriptSecurityManager::CheckLoadURIStr
   uint32_t flags[] = {nsIURIFixup::FIXUP_FLAG_NONE,
                       nsIURIFixup::FIXUP_FLAG_FIX_SCHEME_TYPOS,
                       nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
                       nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI,
                       nsIURIFixup::FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
                           nsIURIFixup::FIXUP_FLAGS_MAKE_ALTERNATE_URI};
 
   for (uint32_t i = 0; i < ArrayLength(flags); ++i) {
-    rv = fixup->CreateFixupURI(aTargetURIStr, flags[i], nullptr,
+    uint32_t fixupFlags = flags[i];
+    if (aPrincipal->OriginAttributesRef().mPrivateBrowsingId > 0) {
+      fixupFlags |= nsIURIFixup::FIXUP_FLAG_PRIVATE_CONTEXT;
+    }
+    rv = fixup->CreateFixupURI(aTargetURIStr, fixupFlags, nullptr,
                                getter_AddRefs(target));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = CheckLoadURIWithPrincipal(aPrincipal, target, aFlags);
     if (rv == NS_ERROR_DOM_BAD_URI) {
       // Don't warn because NS_ERROR_DOM_BAD_URI is one of the expected
       // return values.
       return rv;
--- a/docshell/base/nsDefaultURIFixup.cpp
+++ b/docshell/base/nsDefaultURIFixup.cpp
@@ -115,17 +115,17 @@ static bool MaybeTabSeparatedContent(con
 NS_IMETHODIMP
 nsDefaultURIFixup::GetFixupURIInfo(const nsACString& aStringURI,
                                    uint32_t aFixupFlags,
                                    nsIInputStream** aPostData,
                                    nsIURIFixupInfo** aInfo) {
   NS_ENSURE_ARG(!aStringURI.IsEmpty());
 
   nsresult rv;
-
+  bool isPrivateContext = aFixupFlags & FIXUP_FLAG_PRIVATE_CONTEXT;
   nsAutoCString uriString(aStringURI);
 
   // Eliminate embedded newlines, which single-line text fields now allow:
   uriString.StripCRLF();
   // Cleanup the empty spaces and tabs that might be on each end:
   uriString.Trim(" \t");
 
   NS_ENSURE_TRUE(!uriString.IsEmpty(), NS_ERROR_FAILURE);
@@ -274,17 +274,18 @@ nsDefaultURIFixup::GetFixupURIInfo(const
       }
       // 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) {
         bool hasUserPassword = HasUserPassword(uriString);
         if (!hasUserPassword) {
-          TryKeywordFixupForURIInfo(uriString, info, aPostData);
+          TryKeywordFixupForURIInfo(uriString, info, isPrivateContext,
+                                    aPostData);
         } else {
           // If the given URL has a user:password we can't just pass it to the
           // external protocol handler; we'll try using it with http instead
           // later
           info->mFixedURI = nullptr;
         }
       }
     }
@@ -330,17 +331,18 @@ nsDefaultURIFixup::GetFixupURIInfo(const
     }
   }
 
   // See if it is a keyword
   // Test whether keywords need to be fixed up
   if (StaticPrefs::keyword_enabled() &&
       (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP) &&
       !inputHadDuffProtocol) {
-    if (NS_SUCCEEDED(KeywordURIFixup(uriString, info, aPostData)) &&
+    if (NS_SUCCEEDED(
+            KeywordURIFixup(uriString, info, isPrivateContext, 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
 
@@ -352,17 +354,18 @@ nsDefaultURIFixup::GetFixupURIInfo(const
     info->mPreferredURI = info->mFixedURI;
     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 (StaticPrefs::keyword_enabled() &&
       (aFixupFlags & FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP)) {
-    rv = TryKeywordFixupForURIInfo(aStringURI, info, aPostData);
+    rv = TryKeywordFixupForURIInfo(aStringURI, info, isPrivateContext,
+                                   aPostData);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 nsDefaultURIFixup::WebNavigationFlagsToFixupFlags(const nsACString& aStringURI,
                                                   uint32_t aDocShellFlags,
@@ -381,16 +384,17 @@ nsDefaultURIFixup::WebNavigationFlagsToF
     *aFixupFlags |= FIXUP_FLAG_FIX_SCHEME_TYPOS;
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDefaultURIFixup::KeywordToURI(const nsACString& aKeyword,
+                                bool aIsPrivateContext,
                                 nsIInputStream** aPostData,
                                 nsIURIFixupInfo** aInfo) {
   RefPtr<nsDefaultURIFixupInfo> info = new nsDefaultURIFixupInfo(aKeyword);
   NS_ADDREF(*aInfo = info);
 
   if (aPostData) {
     *aPostData = nullptr;
   }
@@ -407,18 +411,18 @@ nsDefaultURIFixup::KeywordToURI(const ns
     dom::ContentChild* contentChild = dom::ContentChild::GetSingleton();
     if (!contentChild) {
       return NS_ERROR_NOT_AVAILABLE;
     }
 
     RefPtr<nsIInputStream> postData;
     Maybe<ipc::URIParams> uri;
     nsAutoString providerName;
-    if (!contentChild->SendKeywordToURI(keyword, &providerName, &postData,
-                                        &uri)) {
+    if (!contentChild->SendKeywordToURI(keyword, aIsPrivateContext,
+                                        &providerName, &postData, &uri)) {
       return NS_ERROR_FAILURE;
     }
 
     CopyUTF8toUTF16(keyword, info->mKeywordAsSent);
     info->mKeywordProviderName = providerName;
 
     if (aPostData) {
       postData.forget(aPostData);
@@ -428,18 +432,24 @@ nsDefaultURIFixup::KeywordToURI(const ns
     info->mPreferredURI = temp.forget();
     return NS_OK;
   }
 
   // Try falling back to the search service's default search engine
   nsCOMPtr<nsISearchService> searchSvc =
       do_GetService("@mozilla.org/browser/search-service;1");
   if (searchSvc) {
+    // We must use an appropriate search engine depending on the private
+    // context.
     nsCOMPtr<nsISearchEngine> defaultEngine;
-    searchSvc->GetDefaultEngine(getter_AddRefs(defaultEngine));
+    if (aIsPrivateContext) {
+      searchSvc->GetDefaultPrivateEngine(getter_AddRefs(defaultEngine));
+    } else {
+      searchSvc->GetDefaultEngine(getter_AddRefs(defaultEngine));
+    }
     if (defaultEngine) {
       nsCOMPtr<nsISearchSubmission> submission;
       nsAutoString responseType;
       // We allow default search plugins to specify alternate
       // parameters that are specific to keyword searches.
       NS_NAMED_LITERAL_STRING(mozKeywordSearch,
                               "application/x-moz-keywordsearch");
       bool supportsResponseType = false;
@@ -476,20 +486,20 @@ nsDefaultURIFixup::KeywordToURI(const ns
 
   // 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) {
+    bool aIsPrivateContext, nsIInputStream** aPostData) {
   nsCOMPtr<nsIURIFixupInfo> keywordInfo;
-  nsresult rv =
-      KeywordToURI(aURIString, aPostData, getter_AddRefs(keywordInfo));
+  nsresult rv = KeywordToURI(aURIString, aIsPrivateContext, aPostData,
+                             getter_AddRefs(keywordInfo));
   if (NS_SUCCEEDED(rv)) {
     keywordInfo->GetKeywordProviderName(aFixupInfo->mKeywordProviderName);
     keywordInfo->GetKeywordAsSent(aFixupInfo->mKeywordAsSent);
     keywordInfo->GetPreferredURI(getter_AddRefs(aFixupInfo->mPreferredURI));
   }
   return rv;
 }
 
@@ -758,16 +768,17 @@ bool nsDefaultURIFixup::PossiblyHostPort
   }
 
   // Yes, it's possibly a host:port url
   return true;
 }
 
 nsresult nsDefaultURIFixup::KeywordURIFixup(const nsACString& aURIString,
                                             nsDefaultURIFixupInfo* aFixupInfo,
+                                            bool aIsPrivateContext,
                                             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"
@@ -901,24 +912,24 @@ nsresult nsDefaultURIFixup::KeywordURIFi
   // We do keyword lookups if a space or quote preceded the dot, colon
   // or question mark (or if the latter is not found, or if the input starts
   // with a question mark)
   if (((firstSpaceLoc < firstDotLoc || firstQuoteLoc < firstDotLoc) &&
        (firstSpaceLoc < firstColonLoc || firstQuoteLoc < firstColonLoc) &&
        (firstSpaceLoc < firstQMarkLoc || firstQuoteLoc < firstQMarkLoc)) ||
       firstQMarkLoc == 0) {
     rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo,
-                                   aPostData);
+                                   aIsPrivateContext, aPostData);
     // ... or when the asciiHost is the same as displayHost and there are no
     // characters from [a-z][A-Z]
   } else if (isValidHost && isValidDisplayHost && !hasAsciiAlpha &&
              asciiHost.EqualsIgnoreCase(displayHost.get())) {
     if (!StaticPrefs::browser_fixup_dns_first_for_single_words()) {
       rv = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo,
-                                     aPostData);
+                                     aIsPrivateContext, 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) &&
@@ -932,17 +943,17 @@ nsresult nsDefaultURIFixup::KeywordURIFi
     if (firstDotLoc == uint32_t(kNotFound) &&
         lastSlashLoc != uint32_t(kNotFound) && hasAsciiAlpha && isValidHost) {
       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 = TryKeywordFixupForURIInfo(aFixupInfo->mOriginalInput, aFixupInfo,
-                                   aPostData);
+                                   aIsPrivateContext, aPostData);
   }
   return rv;
 }
 
 bool nsDefaultURIFixup::IsDomainWhitelisted(const nsACString& aAsciiHost,
                                             const uint32_t aDotLoc) {
   if (StaticPrefs::browser_fixup_dns_first_for_single_words()) {
     return true;
--- a/docshell/base/nsDefaultURIFixup.h
+++ b/docshell/base/nsDefaultURIFixup.h
@@ -25,19 +25,20 @@ class nsDefaultURIFixup : public nsIURIF
  private:
   /* additional members */
   nsresult FileURIFixup(const nsACString& aStringURI, nsIURI** aURI);
   nsresult ConvertFileToStringURI(const nsACString& aIn, nsCString& aResult);
   nsresult FixupURIProtocol(const nsACString& aIn,
                             nsDefaultURIFixupInfo* aFixupInfo, nsIURI** aURI);
   nsresult KeywordURIFixup(const nsACString& aStringURI,
                            nsDefaultURIFixupInfo* aFixupInfo,
-                           nsIInputStream** aPostData);
+                           bool aIsPrivateContext, nsIInputStream** aPostData);
   nsresult TryKeywordFixupForURIInfo(const nsACString& aStringURI,
                                      nsDefaultURIFixupInfo* aFixupInfo,
+                                     bool aIsPrivateContext,
                                      nsIInputStream** aPostData);
   bool PossiblyHostPortUrl(const nsACString& aUrl);
   bool MakeAlternateURI(nsCOMPtr<nsIURI>& aURI);
   bool IsDomainWhitelisted(const nsACString& aAsciiHost,
                            const uint32_t aDotLoc);
 };
 
 class nsDefaultURIFixupInfo : public nsIURIFixupInfo {
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -6626,17 +6626,17 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
             (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,
+            sURIFixup->KeywordToURI(mOriginalUriString, UsePrivateBrowsing(),
                                     getter_AddRefs(newPostData),
                                     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
@@ -6646,20 +6646,22 @@ nsresult nsDocShell::EndPageLoad(nsIWebP
             // Since we don't have access to the exact original string
             // that was entered by the user, this will just have to do.
             bool isACE;
             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),
+              sURIFixup->KeywordToURI(utf8Host, UsePrivateBrowsing(),
+                                      getter_AddRefs(newPostData),
                                       getter_AddRefs(info));
             } else {
-              sURIFixup->KeywordToURI(host, getter_AddRefs(newPostData),
+              sURIFixup->KeywordToURI(host, UsePrivateBrowsing(),
+                                      getter_AddRefs(newPostData),
                                       getter_AddRefs(info));
             }
           }
 
           info->GetPreferredURI(getter_AddRefs(newURI));
           if (newURI) {
             info->GetKeywordAsSent(keywordAsSent);
             info->GetKeywordProviderName(keywordProviderName);
--- a/docshell/base/nsIURIFixup.idl
+++ b/docshell/base/nsIURIFixup.idl
@@ -85,22 +85,27 @@ interface nsIURIFixup : nsISupports
 
     /**
      * Tell the fixup to make an alternate URI from the input URI, for example
      * to turn foo into www.foo.com.
      */
     const unsigned long FIXUP_FLAGS_MAKE_ALTERNATE_URI = 2;
 
     /*
+     * Set when the fixup happens in a private context, the used search engine
+     * may differ in this case. Not all consumers care about this, because they
+     * may not want the url to be transformed in a search.
+     */
+    const unsigned long FIXUP_FLAG_PRIVATE_CONTEXT = 4;
+
+    /*
      * Fix common scheme typos.
      */
     const unsigned long FIXUP_FLAG_FIX_SCHEME_TYPOS = 8;
 
-    /* NB: If adding an extra flag, 4 is free (again) */
-
     /**
      * Converts an internal URI (e.g. one that has a username and password in
      * it) into one which we can expose to the user, for example on the URL bar.
      *
      * @param  aURI       The URI to be converted
      * @return nsIURI     The converted, exposable URI
      * @throws NS_ERROR_MALFORMED_URI when the exposable portion of aURI is malformed
      * @throws NS_ERROR_UNKNOWN_PROTOCOL when we can't get a protocol handler service
@@ -147,23 +152,25 @@ interface nsIURIFixup : nsISupports
         in AUTF8String aURIText, in unsigned long aDocShellFlags);
 
     /**
      * Converts the specified keyword string into a URI.  Note that it's the
      * caller's responsibility to check whether keywords are enabled and
      * whether aKeyword is a sensible keyword.
      *
      * @param aKeyword  The keyword string to convert into a URI
+     * @param aIsPrivateContext Whether this is invoked from a private context.
      * @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.
      */
     nsIURIFixupInfo keywordToURI(in AUTF8String aKeyword,
+                                 [optional] in boolean aIsPrivateContext,
                                  [optional] out nsIInputStream aPostData);
 
     /**
      * Returns true if the specified domain is whitelisted and false otherwise.
      * A whitelisted domain is relevant when we have a single word and can't be
      * sure whether to treat the word as a host name or should instead be
      * treated as a search term.
      *
--- a/docshell/test/unit/test_nsDefaultURIFixup_info.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_info.js
@@ -2,33 +2,40 @@ const { AddonTestUtils } = ChromeUtils.i
   "resource://testing-common/AddonTestUtils.jsm"
 );
 const { AppConstants } = ChromeUtils.import(
   "resource://gre/modules/AppConstants.jsm"
 );
 
 const kSearchEngineID = "test_urifixup_search_engine";
 const kSearchEngineURL = "http://www.example.org/?search={searchTerms}";
+const kPrivateSearchEngineID = "test_urifixup_search_engine_private";
+const kPrivateSearchEngineURL = "http://www.example.org/?private={searchTerms}";
 const kForceHostLookup = "browser.fixup.dns_first_for_single_words";
 
 AddonTestUtils.init(this);
 AddonTestUtils.overrideCertDB();
 AddonTestUtils.createAppInfo(
   "xpcshell@tests.mozilla.org",
   "XPCShell",
   "1",
   "42"
 );
 
 // TODO(bug 1522134), this test should also use
 // combinations of the following flags.
 var flagInputs = [
   Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP,
+  Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
+    Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT,
   Services.uriFixup.FIXUP_FLAGS_MAKE_ALTERNATE_URI,
   Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS,
+  // This should not really generate a search, but it does, see Bug 1588118.
+  Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
+    Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT,
 ];
 
 /*
   The following properties are supported for these test cases:
   {
     input: "", // Input string, required
     fixedURI: "", // Expected fixedURI
     alternateURI: "", // Expected alternateURI
@@ -601,55 +608,69 @@ function sanitize(input) {
   return input.replace(/\r|\n/g, "").trim();
 }
 
 add_task(async function setup() {
   var prefList = [
     "browser.fixup.typo.scheme",
     "keyword.enabled",
     "browser.fixup.domainwhitelist.whitelisted",
+    "browser.search.separatePrivateDefault",
   ];
   for (let pref of prefList) {
     Services.prefs.setBoolPref(pref, true);
   }
 
   await AddonTestUtils.promiseStartupManager();
 
   Services.io
     .getProtocolHandler("resource")
     .QueryInterface(Ci.nsIResProtocolHandler)
     .setSubstitution(
       "search-extensions",
       Services.io.newURI("chrome://mozapps/locale/searchextensions/")
     );
 
-  await Services.search.addEngineWithDetails(kSearchEngineID, {
-    method: "get",
-    template: kSearchEngineURL,
-  });
+  var oldCurrentEngine = await Services.search.getDefault();
+  var oldPrivateEngine = await Services.search.getDefaultPrivate();
 
-  var oldCurrentEngine = await Services.search.getDefault();
-  await Services.search.setDefault(
-    Services.search.getEngineByName(kSearchEngineID)
+  let newCurrentEngine = await Services.search.addEngineWithDetails(
+    kSearchEngineID,
+    {
+      method: "get",
+      template: kSearchEngineURL,
+    }
   );
+  await Services.search.setDefault(newCurrentEngine);
+
+  let newPrivateEngine = await Services.search.addEngineWithDetails(
+    kPrivateSearchEngineID,
+    {
+      method: "get",
+      template: kPrivateSearchEngineURL,
+    }
+  );
+  await Services.search.setDefaultPrivate(newPrivateEngine);
 
   var selectedName = (await Services.search.getDefault()).name;
   Assert.equal(selectedName, kSearchEngineID);
 
   registerCleanupFunction(async function() {
     if (oldCurrentEngine) {
       await Services.search.setDefault(oldCurrentEngine);
     }
-    let engine = Services.search.getEngineByName(kSearchEngineID);
-    if (engine) {
-      await Services.search.removeEngine(engine);
+    if (oldPrivateEngine) {
+      await Services.search.setDefault(oldPrivateEngine);
     }
+    await Services.search.removeEngine(newCurrentEngine);
+    await Services.search.removeEngine(newPrivateEngine);
     Services.prefs.clearUserPref("keyword.enabled");
     Services.prefs.clearUserPref("browser.fixup.typo.scheme");
     Services.prefs.clearUserPref(kForceHostLookup);
+    Services.prefs.clearUserPref("browser.search.separatePrivateDefault");
   });
 });
 
 var gSingleWordHostLookup = false;
 add_task(async function run_test() {
   // Only keywordlookup things should be affected by requiring a DNS lookup for single-word hosts:
   info(
     "Check only keyword lookup testcases should be affected by requiring DNS for single hosts"
@@ -778,22 +799,41 @@ function do_single_test_run() {
               /%20/g,
               "+"
             );
             // If the input starts with `?`, then URIInfo.preferredURI.spec will omit it
             // In order to test this behaviour, remove `?` only if it is the first character
             if (urlparamInput.startsWith("%3F")) {
               urlparamInput = urlparamInput.replace("%3F", "");
             }
-            let searchURL = kSearchEngineURL.replace(
+            let isPrivate =
+              flags & Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+            let searchEngineUrl = isPrivate
+              ? kPrivateSearchEngineURL
+              : kSearchEngineURL;
+            let searchURL = searchEngineUrl.replace(
               "{searchTerms}",
               urlparamInput
             );
             let spec = URIInfo.preferredURI.spec.replace(/%27/g, "'");
             Assert.equal(spec, searchURL, "should get correct search URI");
+            let providerName = isPrivate
+              ? kPrivateSearchEngineID
+              : kSearchEngineID;
+            Assert.equal(
+              URIInfo.keywordProviderName,
+              providerName,
+              "should get correct provider name"
+            );
+            // Also check keywordToURI() uses the right engine.
+            let kwInfo = Services.uriFixup.keywordToURI(
+              urlparamInput,
+              isPrivate
+            );
+            Assert.equal(kwInfo.providerName, URIInfo.providerName);
           } else {
             Assert.equal(
               URIInfo.preferredURI,
               null,
               "not expecting a preferred URI"
             );
           }
         } else {
--- a/docshell/test/unit/test_nsDefaultURIFixup_search.js
+++ b/docshell/test/unit/test_nsDefaultURIFixup_search.js
@@ -2,16 +2,18 @@ const { AppConstants } = ChromeUtils.imp
   "resource://gre/modules/AppConstants.jsm"
 );
 const { AddonTestUtils } = ChromeUtils.import(
   "resource://testing-common/AddonTestUtils.jsm"
 );
 
 const kSearchEngineID = "test_urifixup_search_engine";
 const kSearchEngineURL = "http://www.example.org/?search={searchTerms}";
+const kPrivateSearchEngineID = "test_urifixup_search_engine_private";
+const kPrivateSearchEngineURL = "http://www.example.org/?private={searchTerms}";
 
 var isWin = AppConstants.platform == "win";
 
 var data = [
   {
     // Valid should not be changed.
     wrong: "https://example.com/this/is/a/test.html",
     fixed: "https://example.com/this/is/a/test.html",
@@ -20,16 +22,26 @@ var data = [
     // Unrecognized protocols should be changed.
     wrong: "whatever://this/is/a/test.html",
     fixed: kSearchEngineURL.replace(
       "{searchTerms}",
       encodeURIComponent("whatever://this/is/a/test.html")
     ),
   },
 
+  {
+    // Unrecognized protocols should be changed.
+    wrong: "whatever://this/is/a/test.html",
+    fixed: kPrivateSearchEngineURL.replace(
+      "{searchTerms}",
+      encodeURIComponent("whatever://this/is/a/test.html")
+    ),
+    inPrivateBrowsing: true,
+  },
+
   // The following tests check that when a user:password is present in the URL
   // `user:` isn't treated as an unknown protocol thus leaking the user and
   // password to the search engine.
   {
     wrong: "user:pass@example.com/this/is/a/test.html",
     fixed: "http://user:pass@example.com/this/is/a/test.html",
   },
   {
@@ -101,52 +113,65 @@ AddonTestUtils.createAppInfo(
   "1",
   "42"
 );
 
 add_task(async function setup() {
   await AddonTestUtils.promiseStartupManager();
 
   Services.prefs.setBoolPref("keyword.enabled", true);
+  Services.prefs.setBoolPref("browser.search.separatePrivateDefault", true);
+
   Services.io
     .getProtocolHandler("resource")
     .QueryInterface(Ci.nsIResProtocolHandler)
     .setSubstitution(
       "search-extensions",
       Services.io.newURI("chrome://mozapps/locale/searchextensions/")
     );
 
-  await Services.search.addEngineWithDetails(kSearchEngineID, {
-    method: "get",
-    template: kSearchEngineURL,
-  });
+  var oldCurrentEngine = await Services.search.getDefault();
+  var oldPrivateEngine = await Services.search.getDefaultPrivate();
 
-  var oldCurrentEngine = await Services.search.getDefault();
-  await Services.search.setDefault(
-    Services.search.getEngineByName(kSearchEngineID)
+  let newCurrentEngine = await Services.search.addEngineWithDetails(
+    kSearchEngineID,
+    {
+      method: "get",
+      template: kSearchEngineURL,
+    }
   );
+  await Services.search.setDefault(newCurrentEngine);
 
-  var selectedName = (await Services.search.getDefault()).name;
-  Assert.equal(selectedName, kSearchEngineID);
+  let newPrivateEngine = await Services.search.addEngineWithDetails(
+    kPrivateSearchEngineID,
+    {
+      method: "get",
+      template: kPrivateSearchEngineURL,
+    }
+  );
+  await Services.search.setDefaultPrivate(newPrivateEngine);
 
   registerCleanupFunction(async function() {
     if (oldCurrentEngine) {
       await Services.search.setDefault(oldCurrentEngine);
     }
-    let engine = Services.search.getEngineByName(kSearchEngineID);
-    if (engine) {
-      await Services.search.removeEngine(engine);
+    if (oldPrivateEngine) {
+      await Services.search.setDefault(oldPrivateEngine);
     }
+    await Services.search.removeEngine(newCurrentEngine);
+    await Services.search.removeEngine(newPrivateEngine);
     Services.prefs.clearUserPref("keyword.enabled");
+    Services.prefs.clearUserPref("browser.search.separatePrivateDefault");
   });
 });
 
 // Make sure we fix what needs fixing
 add_task(function test_fix_unknown_schemes() {
   for (let i = 0; i < len; ++i) {
     let item = data[i];
-    let result = Services.uriFixup.createFixupURI(
-      item.wrong,
-      Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS
-    ).spec;
+    let flags = Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
+    if (item.inPrivateBrowsing) {
+      flags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+    }
+    let result = Services.uriFixup.createFixupURI(item.wrong, flags).spec;
     Assert.equal(result, item.fixed);
   }
 });
--- a/dom/base/ContentAreaDropListener.jsm
+++ b/dom/base/ContentAreaDropListener.jsm
@@ -67,16 +67,19 @@ ContentAreaDropListener.prototype = {
           // For plain text, there are 2 cases:
           //   * if there is at least one URI:
           //       Add all URIs, ignoring non-URI lines, so that all URIs
           //       are opened in tabs.
           //   * if there's no URI:
           //       Add the entire text as a single entry, so that the entire
           //       text is searched.
           let hasURI = false;
+          // We don't care whether we are in a private context, because we are
+          // only using fixedURI and thus there's no risk to use the wrong
+          // search engine.
           let flags =
             Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
             Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
           for (let line of lines) {
             let info = Services.uriFixup.getFixupURIInfo(line, flags);
             if (info.fixedURI) {
               // Use the original line here, and let the caller decide
               // whether to perform fixup or not.
@@ -124,16 +127,19 @@ ContentAreaDropListener.prototype = {
     // URI from the dropped string. If that succeeds, we're
     // dropping a URI and we need to do a security check to make
     // sure the source document can load the dropped URI.
     uriString = uriString.replace(/^\s*|\s*$/g, "");
 
     // Apply URI fixup so that this validation prevents bad URIs even if the
     // similar fixup is applied later, especialy fixing typos up will convert
     // non-URI to URI.
+    // We don't know if the uri comes from a private context, but luckily we
+    // are only using fixedURI, so there's no risk to use the wrong search
+    // engine.
     let fixupFlags =
       Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
       Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
     let info = Services.uriFixup.getFixupURIInfo(uriString, fixupFlags);
     if (!info.fixedURI || info.keywordProviderName) {
       // Loading a keyword search should always be fine for all cases.
       return uriString;
     }
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4257,29 +4257,31 @@ nsresult ContentParent::DoSendAsyncMessa
   if (!SendAsyncMessage(nsString(aMessage), cpows, Principal(aPrincipal),
                         data)) {
     return NS_ERROR_UNEXPECTED;
   }
   return NS_OK;
 }
 
 mozilla::ipc::IPCResult ContentParent::RecvKeywordToURI(
-    const nsCString& aKeyword, nsString* aProviderName,
-    RefPtr<nsIInputStream>* aPostData, Maybe<URIParams>* aURI) {
+    const nsCString& aKeyword, const bool& aIsPrivateContext,
+    nsString* aProviderName, RefPtr<nsIInputStream>* aPostData,
+    Maybe<URIParams>* aURI) {
   *aPostData = nullptr;
   *aURI = Nothing();
 
   nsCOMPtr<nsIURIFixup> fixup = components::URIFixup::Service();
   if (!fixup) {
     return IPC_OK();
   }
 
   nsCOMPtr<nsIURIFixupInfo> info;
 
-  if (NS_FAILED(fixup->KeywordToURI(aKeyword, getter_AddRefs(*aPostData),
+  if (NS_FAILED(fixup->KeywordToURI(aKeyword, aIsPrivateContext,
+                                    getter_AddRefs(*aPostData),
                                     getter_AddRefs(info)))) {
     return IPC_OK();
   }
   info->GetKeywordProviderName(*aProviderName);
 
   nsCOMPtr<nsIURI> uri;
   info->GetPreferredURI(getter_AddRefs(uri));
   SerializeURI(uri, *aURI);
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -1036,16 +1036,17 @@ class ContentParent final : public PCont
       BrowsingContext* aContext, BrowsingContext::Transaction&& aTransaction,
       uint64_t aEpoch);
 
   mozilla::ipc::IPCResult RecvFirstIdle();
 
   mozilla::ipc::IPCResult RecvDeviceReset();
 
   mozilla::ipc::IPCResult RecvKeywordToURI(const nsCString& aKeyword,
+                                           const bool& aIsPrivateContext,
                                            nsString* aProviderName,
                                            RefPtr<nsIInputStream>* aPostData,
                                            Maybe<URIParams>* aURI);
 
   mozilla::ipc::IPCResult RecvNotifyKeywordSearchLoading(
       const nsString& aProvider, const nsString& aKeyword);
 
   mozilla::ipc::IPCResult RecvCopyFavicon(
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -1006,17 +1006,17 @@ parent:
     // Notify the parent of the presence or absence of private docshells
     async PrivateDocShellsExist(bool aExist);
 
     // Tell the parent that the child has gone idle for the first time.
     async FirstIdle();
 
     async DeviceReset();
 
-    sync KeywordToURI(nsCString keyword)
+    sync KeywordToURI(nsCString keyword, bool isPrivateContext)
         returns (nsString providerName, nsIInputStream postData, URIParams? uri);
 
     sync NotifyKeywordSearchLoading(nsString providerName, nsString keyword);
 
     async CopyFavicon(URIParams oldURI, URIParams newURI, Principal aLoadingPrincipal, bool isPrivate);
 
     /**
      * Notifies the parent about a recording device is starting or shutdown.
--- a/dom/webbrowserpersist/nsWebBrowserPersist.h
+++ b/dom/webbrowserpersist/nsWebBrowserPersist.h
@@ -70,17 +70,16 @@ class nsWebBrowserPersist final : public
                                       char16_t** aExt);
 
   struct CleanupData;
   struct DocData;
   struct OutputData;
   struct UploadData;
   struct URIData;
   struct WalkData;
-  struct URIFixupData;
 
   class OnWalk;
   class OnWrite;
   class FlatURIMap;
   friend class OnWalk;
   friend class OnWrite;
 
   nsresult SaveDocumentDeferred(mozilla::UniquePtr<WalkData>&& aData);
--- a/toolkit/components/places/UnifiedComplete.jsm
+++ b/toolkit/components/places/UnifiedComplete.jsm
@@ -1914,16 +1914,19 @@ Search.prototype = {
     // The user may have typed something like "word?" to run a search, we should
     // not convert that to a url.
     if (this.hasBehavior("search") && this.hasBehavior("restrict")) {
       return false;
     }
     let flags =
       Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS |
       Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
+    if (this._inPrivateWindow) {
+      flags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+    }
     let fixupInfo = null;
     let searchUrl = this._trimmedOriginalSearchString;
     try {
       fixupInfo = Services.uriFixup.getFixupURIInfo(searchUrl, flags);
     } catch (e) {
       if (
         e.result == Cr.NS_ERROR_MALFORMED_URI &&
         !UrlbarPrefs.get("keyword.enabled")
--- a/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
+++ b/toolkit/components/remotebrowserutils/RemoteWebNavigation.jsm
@@ -83,36 +83,38 @@ RemoteWebNavigation.prototype = {
   loadURI(aURI, aLoadURIOptions) {
     let uri;
     try {
       let fixup = Cc["@mozilla.org/docshell/urifixup;1"].getService();
       let fixupFlags = fixup.webNavigationFlagsToFixupFlags(
         aURI,
         aLoadURIOptions.loadFlags
       );
+      let isBrowserPrivate = PrivateBrowsingUtils.isBrowserPrivate(
+        this._browser
+      );
+      if (isBrowserPrivate) {
+        fixupFlags |= Services.uriFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+      }
       uri = fixup.createFixupURI(aURI, fixupFlags);
 
       // We know the url is going to be loaded, let's start requesting network
       // connection before the content process asks.
       // Note that we might have already setup the speculative connection in
       // some cases, especially when the url is from location bar or its popup
       // menu.
       if (uri.schemeIs("http") || uri.schemeIs("https")) {
         let principal = aLoadURIOptions.triggeringPrincipal;
         // We usually have a triggeringPrincipal assigned, but in case we
         // don't have one or if it's a SystemPrincipal, let's create it with OA
         // inferred from the current context.
         if (!principal || principal.isSystemPrincipal) {
           let attrs = {
             userContextId: this._browser.getAttribute("usercontextid") || 0,
-            privateBrowsingId: PrivateBrowsingUtils.isBrowserPrivate(
-              this._browser
-            )
-              ? 1
-              : 0,
+            privateBrowsingId: isBrowserPrivate ? 1 : 0,
           };
           principal = Services.scriptSecurityManager.createContentPrincipal(
             uri,
             attrs
           );
         }
         Services.io.speculativeConnect(uri, principal, null);
       }
--- a/toolkit/modules/BrowserUtils.jsm
+++ b/toolkit/modules/BrowserUtils.jsm
@@ -793,16 +793,22 @@ var BrowserUtils = {
     let url = aURL.replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1");
 
     // remove http://
     if (!url.startsWith("http://")) {
       return url;
     }
     let urlWithoutProtocol = url.substring(7);
 
+    // It doesn't really matter which search engine is used here, thus it's ok
+    // to ignore whether we are in a private context. The keyword lookup is only
+    // used to differentiate between whitelisted and not whitelisted hosts.
+    // For example, if "someword" is not a whitelisted host, setting the urlbar
+    // value to "http://someword" should not trim it, because otherwise
+    // confirming the urlbar value would end up searching for "someword".
     let flags =
       Services.uriFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP |
       Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
     let fixedUpURL, expectedURLSpec;
     try {
       fixedUpURL = Services.uriFixup.createFixupURI(urlWithoutProtocol, flags);
       expectedURLSpec = Services.io.newURI(aURL).displaySpec;
     } catch (ex) {
--- a/toolkit/modules/E10SUtils.jsm
+++ b/toolkit/modules/E10SUtils.jsm
@@ -6,16 +6,22 @@
 
 var EXPORTED_SYMBOLS = ["E10SUtils"];
 
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
 const { XPCOMUtils } = ChromeUtils.import(
   "resource://gre/modules/XPCOMUtils.jsm"
 );
 
+ChromeUtils.defineModuleGetter(
+  this,
+  "PrivateBrowsingUtils",
+  "resource://gre/modules/PrivateBrowsingUtils.jsm"
+);
+
 XPCOMUtils.defineLazyPreferenceGetter(
   this,
   "useSeparateFileUriProcess",
   "browser.tabs.remote.separateFileUriProcess",
   false
 );
 XPCOMUtils.defineLazyPreferenceGetter(
   this,
@@ -561,16 +567,19 @@ var E10SUtils = {
     try {
       let fixupFlags = Ci.nsIURIFixup.FIXUP_FLAG_NONE;
       if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP) {
         fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_ALLOW_KEYWORD_LOOKUP;
       }
       if (flags & Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS) {
         fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS;
       }
+      if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
+        fixupFlags |= Ci.nsIURIFixup.FIXUP_FLAG_PRIVATE_CONTEXT;
+      }
       uriObject = Services.uriFixup.createFixupURI(uri, fixupFlags);
       // Note that I had thought that we could set uri = uriObject.spec here, to
       // save on fixup later on, but that changes behavior and breaks tests.
       requiredRemoteType = this.getRemoteTypeForURIObject(
         uriObject,
         multiProcess,
         remoteSubframes,
         currentRemoteType,