Commit 10bcb5dc authored by Ryan Sturm's avatar Ryan Sturm Committed by Commit Bot

Adding a call from ChromeACProvider to Search Prefetch service

This is called when the AC matches change. The result will be used in
the future to check top result, all results gone (i.e., we can cancel
ongoing prefetches).

Bug: 1138631
Change-Id: I7b6bad212888eac36756f41f2f534233df596b04
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2493461
Commit-Queue: Ryan Sturm <ryansturm@chromium.org>
Reviewed-by: default avatarJustin Donnelly <jdonnelly@chromium.org>
Reviewed-by: default avatarRobert Ogden <robertogden@chromium.org>
Cr-Commit-Position: refs/heads/master@{#820409}
parent 0e38f00c
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/history/top_sites_factory.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_key.h" #include "chrome/browser/profiles/profile_key.h"
#include "chrome/browser/query_tiles/tile_service_factory.h" #include "chrome/browser/query_tiles/tile_service_factory.h"
...@@ -461,6 +463,16 @@ bool ChromeAutocompleteProviderClient::IsBrowserUpdateAvailable() const { ...@@ -461,6 +463,16 @@ bool ChromeAutocompleteProviderClient::IsBrowserUpdateAvailable() const {
#endif #endif
} }
void ChromeAutocompleteProviderClient::OnAutocompleteControllerResultReady(
AutocompleteController* controller) {
auto* search_prefetch_service =
SearchPrefetchServiceFactory::GetForProfile(profile_);
// Prefetches result pages that the search provider marked as prefetchable.
if (search_prefetch_service)
search_prefetch_service->OnResultChanged(controller);
}
bool ChromeAutocompleteProviderClient::StrippedURLsAreEqual( bool ChromeAutocompleteProviderClient::StrippedURLsAreEqual(
const GURL& url1, const GURL& url1,
const GURL& url2, const GURL& url2,
......
...@@ -84,6 +84,8 @@ class ChromeAutocompleteProviderClient : public AutocompleteProviderClient { ...@@ -84,6 +84,8 @@ class ChromeAutocompleteProviderClient : public AutocompleteProviderClient {
bool IsTabOpenWithURL(const GURL& url, bool IsTabOpenWithURL(const GURL& url,
const AutocompleteInput* input) override; const AutocompleteInput* input) override;
bool IsBrowserUpdateAvailable() const override; bool IsBrowserUpdateAvailable() const override;
void OnAutocompleteControllerResultReady(
AutocompleteController* controller) override;
// For testing. // For testing.
void set_storage_partition(content::StoragePartition* storage_partition) { void set_storage_partition(content::StoragePartition* storage_partition) {
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h" #include "chrome/browser/prefetch/search_prefetch/prefetched_response_container.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/template_url_service_factory.h"
#include "components/omnibox/browser/autocomplete_controller.h"
#include "components/omnibox/browser/base_search_provider.h"
#include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service.h"
#include "components/variations/net/variations_http_headers.h" #include "components/variations/net/variations_http_headers.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
...@@ -247,3 +249,15 @@ void SearchPrefetchService::DeletePrefetch(base::string16 search_terms) { ...@@ -247,3 +249,15 @@ void SearchPrefetchService::DeletePrefetch(base::string16 search_terms) {
void SearchPrefetchService::ReportError() { void SearchPrefetchService::ReportError() {
last_error_time_ticks_ = base::TimeTicks::Now(); last_error_time_ticks_ = base::TimeTicks::Now();
} }
void SearchPrefetchService::OnResultChanged(
AutocompleteController* controller) {
const auto& result = controller->result();
for (const auto& match : result) {
// TODO(ryansturm): Pass a bool for IsTopResult to limit prefetch to when
// the match is the first item in the omnibox. https://crbug.com/1138649
if (BaseSearchProvider::ShouldPrefetch(match)) {
MaybePrefetchURL(match.destination_url);
}
}
}
...@@ -19,6 +19,8 @@ class Profile; ...@@ -19,6 +19,8 @@ class Profile;
class GURL; class GURL;
class PrefetchedResponseContainer; class PrefetchedResponseContainer;
class AutocompleteController;
enum class SearchPrefetchStatus { enum class SearchPrefetchStatus {
// The request is on the network and may move to any other state. // The request is on the network and may move to any other state.
kInFlight = 1, kInFlight = 1,
...@@ -36,6 +38,9 @@ class SearchPrefetchService : public KeyedService { ...@@ -36,6 +38,9 @@ class SearchPrefetchService : public KeyedService {
SearchPrefetchService(const SearchPrefetchService&) = delete; SearchPrefetchService(const SearchPrefetchService&) = delete;
SearchPrefetchService& operator=(const SearchPrefetchService&) = delete; SearchPrefetchService& operator=(const SearchPrefetchService&) = delete;
// Called when |controller| has updated information.
void OnResultChanged(AutocompleteController* controller);
// Returns whether the prefetch started or not. // Returns whether the prefetch started or not.
bool MaybePrefetchURL(const GURL& url); bool MaybePrefetchURL(const GURL& url);
......
...@@ -6,15 +6,23 @@ ...@@ -6,15 +6,23 @@
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_feature_list.h" #include "base/test/scoped_feature_list.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/autocomplete/chrome_autocomplete_scheme_classifier.h"
#include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h" #include "chrome/browser/prefetch/search_prefetch/field_trial_settings.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service.h"
#include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h" #include "chrome/browser/prefetch/search_prefetch/search_prefetch_service_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search_engines/template_url_service_factory.h" #include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/location_bar/location_bar.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/search_test_utils.h" #include "chrome/test/base/search_test_utils.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "components/omnibox/browser/autocomplete_input.h"
#include "components/omnibox/browser/autocomplete_match.h"
#include "components/omnibox/browser/autocomplete_provider.h"
#include "components/omnibox/browser/omnibox_popup_model.h"
#include "components/omnibox/browser/omnibox_view.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/search_engines/template_url_service.h" #include "components/search_engines/template_url_service.h"
#include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_task_traits.h"
...@@ -29,6 +37,13 @@ ...@@ -29,6 +37,13 @@
#include "net/test/embedded_test_server/http_response.h" #include "net/test/embedded_test_server/http_response.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace {
constexpr char kSuggestDomain[] = "suggest.com";
constexpr char kSearchDomain[] = "search.com";
constexpr char kOmniboxSuggestPrefetchQuery[] = "porgs";
constexpr char kOmniboxSuggestNonPrefetchQuery[] = "puffins";
} // namespace
class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
public: public:
SearchPrefetchBaseBrowserTest() { SearchPrefetchBaseBrowserTest() {
...@@ -39,12 +54,21 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { ...@@ -39,12 +54,21 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
base::BindRepeating(&SearchPrefetchBaseBrowserTest::HandleSearchRequest, base::BindRepeating(&SearchPrefetchBaseBrowserTest::HandleSearchRequest,
base::Unretained(this))); base::Unretained(this)));
EXPECT_TRUE(search_server_->Start()); EXPECT_TRUE(search_server_->Start());
search_suggest_server_ = std::make_unique<net::EmbeddedTestServer>(
net::EmbeddedTestServer::TYPE_HTTPS);
search_suggest_server_->ServeFilesFromSourceDirectory("chrome/test/data");
search_suggest_server_->RegisterRequestHandler(base::BindRepeating(
&SearchPrefetchBaseBrowserTest::HandleSearchSuggestRequest,
base::Unretained(this)));
EXPECT_TRUE(search_suggest_server_->Start());
} }
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
InProcessBrowserTest::SetUpOnMainThread(); InProcessBrowserTest::SetUpOnMainThread();
host_resolver()->AddRule("search.test", "127.0.0.1"); host_resolver()->AddRule(kSearchDomain, "127.0.0.1");
host_resolver()->AddRule(kSuggestDomain, "127.0.0.1");
TemplateURLService* model = TemplateURLService* model =
TemplateURLServiceFactory::GetForProfile(browser()->profile()); TemplateURLServiceFactory::GetForProfile(browser()->profile());
...@@ -53,9 +77,12 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { ...@@ -53,9 +77,12 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
ASSERT_TRUE(model->loaded()); ASSERT_TRUE(model->loaded());
TemplateURLData data; TemplateURLData data;
data.SetShortName(base::ASCIIToUTF16("search.test")); data.SetShortName(base::ASCIIToUTF16(kSearchDomain));
data.SetKeyword(data.short_name()); data.SetKeyword(data.short_name());
data.SetURL(GetSearchServerQueryURL("{searchTerms}").spec()); data.SetURL(GetSearchServerQueryURL("{searchTerms}").spec());
data.suggestions_url =
search_suggest_server_->GetURL(kSuggestDomain, "/?q={searchTerms}")
.spec();
TemplateURL* template_url = model->Add(std::make_unique<TemplateURL>(data)); TemplateURL* template_url = model->Add(std::make_unique<TemplateURL>(data));
ASSERT_TRUE(template_url); ASSERT_TRUE(template_url);
...@@ -83,11 +110,11 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { ...@@ -83,11 +110,11 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
} }
GURL GetSearchServerQueryURL(const std::string& path) const { GURL GetSearchServerQueryURL(const std::string& path) const {
return search_server_->GetURL("search.test", "/search_page.html?q=" + path); return search_server_->GetURL(kSearchDomain, "/search_page.html?q=" + path);
} }
GURL GetSearchServerQueryURLWithNoQuery(const std::string& path) const { GURL GetSearchServerQueryURLWithNoQuery(const std::string& path) const {
return search_server_->GetURL("search.test", path); return search_server_->GetURL(kSearchDomain, path);
} }
void WaitUntilStatusChanges(base::string16 search_terms) { void WaitUntilStatusChanges(base::string16 search_terms) {
...@@ -102,6 +129,21 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { ...@@ -102,6 +129,21 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
} }
} }
void WaitUntilStatusChangesTo(base::string16 search_terms,
SearchPrefetchStatus status) {
auto* search_prefetch_service =
SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
while (!search_prefetch_service
->GetSearchPrefetchStatusForTesting(search_terms)
.has_value() ||
status != search_prefetch_service
->GetSearchPrefetchStatusForTesting(search_terms)
.value()) {
base::RunLoop run_loop;
run_loop.RunUntilIdle();
}
}
content::WebContents* GetWebContents() const { content::WebContents* GetWebContents() const {
return browser()->tab_strip_model()->GetActiveWebContents(); return browser()->tab_strip_model()->GetActiveWebContents();
} }
...@@ -173,9 +215,52 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest { ...@@ -173,9 +215,52 @@ class SearchPrefetchBaseBrowserTest : public InProcessBrowserTest {
} }
} }
std::unique_ptr<net::test_server::HttpResponse> HandleSearchSuggestRequest(
const net::test_server::HttpRequest& request) {
// |content| is a json request that contains the search suggest response.
// The first item is the query (not used), the second is the results list,
// the third is descriptions, fifth is an extra data dictionary. The
// google:clientdata contains "phi" which is the prefetch index (i.e., which
// suggest can be prefetched).
std::string content = "";
if (request.GetURL().spec().find(kOmniboxSuggestPrefetchQuery) !=
std::string::npos) {
content = R"([
"porgs",
["porgs","porgsandwich"],
["", ""],
[],
{
"google:clientdata": {
"phi": 0
}
}])";
}
if (request.GetURL().spec().find(kOmniboxSuggestNonPrefetchQuery) !=
std::string::npos) {
content = R"([
"puffins",
["puffins","puffinsalad"],
["", ""],
[],
{}])";
}
std::unique_ptr<net::test_server::BasicHttpResponse> resp =
std::make_unique<net::test_server::BasicHttpResponse>();
resp->set_code(net::HTTP_OK);
resp->set_content_type("application/json");
resp->set_content(content);
return resp;
}
std::vector<net::test_server::HttpRequest> search_server_requests_; std::vector<net::test_server::HttpRequest> search_server_requests_;
std::unique_ptr<net::EmbeddedTestServer> search_server_; std::unique_ptr<net::EmbeddedTestServer> search_server_;
std::unique_ptr<net::EmbeddedTestServer> search_suggest_server_;
bool should_hang_requests_ = false; bool should_hang_requests_ = false;
size_t search_server_request_count_ = 0; size_t search_server_request_count_ = 0;
...@@ -494,6 +579,85 @@ IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceEnabledBrowserTest, ...@@ -494,6 +579,85 @@ IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceEnabledBrowserTest,
GetSearchServerQueryURL("other_query"))); GetSearchServerQueryURL("other_query")));
} }
IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceEnabledBrowserTest,
OmniboxEditTriggersPrefetch) {
auto* search_prefetch_service =
SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
std::string search_terms = kOmniboxSuggestPrefetchQuery;
// Trigger an omnibox suggest fetch that has a prefetch hint.
AutocompleteInput input(
base::ASCIIToUTF16(search_terms), metrics::OmniboxEventProto::BLANK,
ChromeAutocompleteSchemeClassifier(browser()->profile()));
LocationBar* location_bar = browser()->window()->GetLocationBar();
OmniboxView* omnibox = location_bar->GetOmniboxView();
AutocompleteController* autocomplete_controller =
omnibox->model()->autocomplete_controller();
// Prevent the stop timer from killing the hints fetch early.
autocomplete_controller->SetStartStopTimerDurationForTesting(
base::TimeDelta::FromSeconds(10));
autocomplete_controller->Start(input);
ui_test_utils::WaitForAutocompleteDone(browser());
EXPECT_TRUE(autocomplete_controller->done());
WaitUntilStatusChangesTo(base::ASCIIToUTF16(search_terms),
SearchPrefetchStatus::kSuccessfullyCompleted);
auto prefetch_status =
search_prefetch_service->GetSearchPrefetchStatusForTesting(
base::ASCIIToUTF16(search_terms));
ASSERT_TRUE(prefetch_status.has_value());
EXPECT_EQ(SearchPrefetchStatus::kSuccessfullyCompleted,
prefetch_status.value());
ui_test_utils::NavigateToURL(browser(),
GetSearchServerQueryURL(search_terms));
auto inner_html = GetDocumentInnerHTML();
EXPECT_FALSE(base::Contains(inner_html, "regular"));
EXPECT_TRUE(base::Contains(inner_html, "prefetch"));
}
IN_PROC_BROWSER_TEST_F(SearchPrefetchServiceEnabledBrowserTest,
OmniboxEditDoesNotTriggersPrefetch) {
auto* search_prefetch_service =
SearchPrefetchServiceFactory::GetForProfile(browser()->profile());
std::string search_terms = kOmniboxSuggestNonPrefetchQuery;
// Trigger an omnibox suggest fetch that does not have a prefetch hint.
AutocompleteInput input(
base::ASCIIToUTF16(search_terms), metrics::OmniboxEventProto::BLANK,
ChromeAutocompleteSchemeClassifier(browser()->profile()));
LocationBar* location_bar = browser()->window()->GetLocationBar();
OmniboxView* omnibox = location_bar->GetOmniboxView();
AutocompleteController* autocomplete_controller =
omnibox->model()->autocomplete_controller();
// Prevent the stop timer from killing the hints fetch early.
autocomplete_controller->SetStartStopTimerDurationForTesting(
base::TimeDelta::FromSeconds(10));
autocomplete_controller->Start(input);
ui_test_utils::WaitForAutocompleteDone(browser());
EXPECT_TRUE(autocomplete_controller->done());
WaitForDuration(base::TimeDelta::FromMilliseconds(100));
auto prefetch_status =
search_prefetch_service->GetSearchPrefetchStatusForTesting(
base::ASCIIToUTF16(search_terms));
EXPECT_FALSE(prefetch_status.has_value());
ui_test_utils::NavigateToURL(browser(),
GetSearchServerQueryURL(search_terms));
auto inner_html = GetDocumentInnerHTML();
EXPECT_TRUE(base::Contains(inner_html, "regular"));
EXPECT_FALSE(base::Contains(inner_html, "prefetch"));
}
class SearchPrefetchServiceZeroCacheTimeBrowserTest class SearchPrefetchServiceZeroCacheTimeBrowserTest
: public SearchPrefetchBaseBrowserTest { : public SearchPrefetchBaseBrowserTest {
public: public:
......
...@@ -1003,3 +1003,8 @@ bool AutocompleteController::OnMemoryDump( ...@@ -1003,3 +1003,8 @@ bool AutocompleteController::OnMemoryDump(
base::trace_event::MemoryAllocatorDump::kUnitsBytes, res); base::trace_event::MemoryAllocatorDump::kUnitsBytes, res);
return true; return true;
} }
void AutocompleteController::SetStartStopTimerDurationForTesting(
base::TimeDelta duration) {
stop_timer_duration_ = duration;
}
...@@ -172,6 +172,9 @@ class AutocompleteController : public AutocompleteProviderListener, ...@@ -172,6 +172,9 @@ class AutocompleteController : public AutocompleteProviderListener,
return last_time_default_match_changed_; return last_time_default_match_changed_;
} }
// Sets the provider timeout duration for future calls to |Start()|.
void SetStartStopTimerDurationForTesting(base::TimeDelta duration);
private: private:
friend class AutocompleteProviderTest; friend class AutocompleteProviderTest;
friend class OmniboxSuggestionButtonRowBrowserTest; friend class OmniboxSuggestionButtonRowBrowserTest;
...@@ -320,12 +323,11 @@ class AutocompleteController : public AutocompleteProviderListener, ...@@ -320,12 +323,11 @@ class AutocompleteController : public AutocompleteProviderListener,
// Timer used to tell the providers to Stop() searching for matches. // Timer used to tell the providers to Stop() searching for matches.
base::OneShotTimer stop_timer_; base::OneShotTimer stop_timer_;
// Amount of time (in ms) between when the user stops typing and // Amount of time between when the user stops typing and when we send Stop()
// when we send Stop() to every provider. This is intended to avoid // to every provider. This is intended to avoid the disruptive effect of
// the disruptive effect of belated omnibox updates, updates that // belated omnibox updates, updates that come after the user has had to time
// come after the user has had to time to read the whole dropdown // to read the whole dropdown and doesn't expect it to change.
// and doesn't expect it to change. base::TimeDelta stop_timer_duration_;
const base::TimeDelta stop_timer_duration_;
// True if a query is not currently running. // True if a query is not currently running.
bool done_; bool done_;
......
...@@ -150,8 +150,8 @@ class AutocompleteProviderClient { ...@@ -150,8 +150,8 @@ class AutocompleteProviderClient {
virtual void StartServiceWorker(const GURL& destination_url) {} virtual void StartServiceWorker(const GURL& destination_url) {}
// Called by |controller| when its results have changed and all providers are // Called by |controller| when its results have changed and all providers are
// done processing the autocomplete request. Chrome ignores this. It's only // done processing the autocomplete request. Used by chrome to inform the
// used in components unit tests. TODO(blundell): remove it. // prefetch service of updated results.
virtual void OnAutocompleteControllerResultReady( virtual void OnAutocompleteControllerResultReady(
AutocompleteController* controller) {} AutocompleteController* controller) {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment