Omnibox - Make Decision about Whether to Query Provider per-provider

In other words, inputs that the user is explicitly sending to a
keyword search engine shouldn't have to pass as extensive a list
of tests as those being sent to the default search engine.  There's
much less of a risk of data leakage here.

BUG=460636

Review URL: https://codereview.chromium.org/983493002

Cr-Commit-Position: refs/heads/master@{#320024}
diff --git a/components/omnibox/search_provider.cc b/components/omnibox/search_provider.cc
index e140fc5..86abbfb 100644
--- a/components/omnibox/search_provider.cc
+++ b/components/omnibox/search_provider.cc
@@ -8,6 +8,7 @@
 #include <cmath>
 
 #include "base/base64.h"
+#include "base/bind.h"
 #include "base/callback.h"
 #include "base/i18n/break_iterator.h"
 #include "base/i18n/case_conversion.h"
@@ -510,15 +511,20 @@
   UpdateDone();
 }
 
-void SearchProvider::Run() {
+void SearchProvider::Run(bool query_is_private) {
   // Start a new request with the current input.
   suggest_results_pending_ = 0;
-  time_suggest_request_sent_ = base::TimeTicks::Now();
 
-  default_fetcher_.reset(CreateSuggestFetcher(kDefaultProviderURLFetcherID,
-      providers_.GetDefaultProviderURL(), input_));
-  keyword_fetcher_.reset(CreateSuggestFetcher(kKeywordProviderURLFetcherID,
-      providers_.GetKeywordProviderURL(), keyword_input_));
+  if (!query_is_private) {
+    default_fetcher_.reset(CreateSuggestFetcher(
+        kDefaultProviderURLFetcherID,
+        providers_.GetDefaultProviderURL(),
+        input_));
+  }
+  keyword_fetcher_.reset(CreateSuggestFetcher(
+      kKeywordProviderURLFetcherID,
+      providers_.GetKeywordProviderURL(),
+      keyword_input_));
 
   // Both the above can fail if the providers have been modified or deleted
   // since the query began.
@@ -527,6 +533,9 @@
     // We only need to update the listener if we're actually done.
     if (done_)
       listener_->OnProviderUpdate(false);
+  } else {
+    // Sent at least one request.
+    time_suggest_request_sent_ = base::TimeTicks::Now();
   }
 }
 
@@ -593,7 +602,8 @@
 }
 
 void SearchProvider::StartOrStopSuggestQuery(bool minimal_changes) {
-  if (!IsQuerySuitableForSuggest()) {
+  bool query_is_private;
+  if (!IsQuerySuitableForSuggest(&query_is_private)) {
     StopSuggest();
     ClearAllResults();
     return;
@@ -634,30 +644,39 @@
   // anyway.
   const base::TimeDelta delay = GetSuggestQueryDelay();
   if (delay <= base::TimeDelta()) {
-    Run();
+    Run(query_is_private);
     return;
   }
-  timer_.Start(FROM_HERE, delay, this, &SearchProvider::Run);
+  timer_.Start(FROM_HERE,
+               delay,
+               base::Bind(&SearchProvider::Run,
+                          base::Unretained(this),
+                          query_is_private));
 }
 
-bool SearchProvider::IsQuerySuitableForSuggest() const {
+bool SearchProvider::IsQuerySuitableForSuggest(bool* query_is_private) const {
+  *query_is_private = IsQueryPotentionallyPrivate();
+
   // Don't run Suggest in incognito mode, if the engine doesn't support it, or
-  // if the user has disabled it.
+  // if the user has disabled it.  Also don't send potentionally private data
+  // to the default search provider.  (It's always okay to send explicit
+  // keyword input to a keyword suggest server, if any.)
   const TemplateURL* default_url = providers_.GetDefaultProviderURL();
   const TemplateURL* keyword_url = providers_.GetKeywordProviderURL();
-  if (client_->IsOffTheRecord() ||
-      ((!default_url || default_url->suggestions_url().empty()) &&
-       (!keyword_url || keyword_url->suggestions_url().empty())) ||
-      !client_->SearchSuggestEnabled())
-    return false;
+  return !client_->IsOffTheRecord() && client_->SearchSuggestEnabled() &&
+      ((default_url && !default_url->suggestions_url().empty() &&
+        !*query_is_private) ||
+       (keyword_url && !keyword_url->suggestions_url().empty()));
+}
 
+bool SearchProvider::IsQueryPotentionallyPrivate() const {
   // If the input type might be a URL, we take extra care so that private data
   // isn't sent to the server.
 
   // FORCED_QUERY means the user is explicitly asking us to search for this, so
   // we assume it isn't a URL and/or there isn't private data.
   if (input_.type() == metrics::OmniboxInputType::FORCED_QUERY)
-    return true;
+    return false;
 
   // Next we check the scheme.  If this is UNKNOWN/URL with a scheme that isn't
   // http/https/ftp, we shouldn't send it.  Sending things like file: and data:
@@ -672,7 +691,7 @@
   if (!LowerCaseEqualsASCII(input_.scheme(), url::kHttpScheme) &&
       !LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
       !LowerCaseEqualsASCII(input_.scheme(), url::kFtpScheme))
-    return (input_.type() == metrics::OmniboxInputType::QUERY);
+    return (input_.type() != metrics::OmniboxInputType::QUERY);
 
   // Don't send URLs with usernames, queries or refs.  Some of these are
   // private, and the Suggest server is unlikely to have any useful results
@@ -688,16 +707,16 @@
       parts.query.is_nonempty() ||
       (parts.ref.is_nonempty() &&
        (input_.type() == metrics::OmniboxInputType::URL)))
-    return false;
+    return true;
 
   // Don't send anything for https except the hostname.  Hostnames are OK
   // because they are visible when the TCP connection is established, but the
   // specific path may reveal private information.
   if (LowerCaseEqualsASCII(input_.scheme(), url::kHttpsScheme) &&
       parts.path.is_nonempty())
-    return false;
+    return true;
 
-  return true;
+  return false;
 }
 
 void SearchProvider::UpdateAllOldResults(bool minimal_changes) {