Commit 248c267f authored by Alexandr Ilin's avatar Alexandr Ilin Committed by Commit Bot

predictors: Request a proxy lookup in parallel with host resolve request

This CL adds an asynchronous proxy lookup request to the PreconnectManager
after the synchronous request was removed in https://crrev.com/c/1165550.
The idea is that we don't need to wait for a host to be resolved before a
preconnect if a proxy is enabled.

Since we don't have a synchronous API for proxy lookup anymore, we issue both
host and proxy requests in parallel. Then we wait until either one of the
requests completes with success or both requests fail.

Bug: 838763
Change-Id: Ib3fa47884ba82d1fc12c62f7fd24dd21c279e9c5
Reviewed-on: https://chromium-review.googlesource.com/1202222
Commit-Queue: Alexandr Ilin <alexilin@chromium.org>
Reviewed-by: default avatarBenoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#589877}
parent 6bb20b5e
...@@ -1132,6 +1132,8 @@ jumbo_split_static_library("browser") { ...@@ -1132,6 +1132,8 @@ jumbo_split_static_library("browser") {
"predictors/predictor_database_factory.h", "predictors/predictor_database_factory.h",
"predictors/predictor_table_base.cc", "predictors/predictor_table_base.cc",
"predictors/predictor_table_base.h", "predictors/predictor_table_base.h",
"predictors/proxy_lookup_client_impl.cc",
"predictors/proxy_lookup_client_impl.h",
"predictors/resolve_host_client_impl.cc", "predictors/resolve_host_client_impl.cc",
"predictors/resolve_host_client_impl.h", "predictors/resolve_host_client_impl.h",
"predictors/resource_prefetch_common.cc", "predictors/resource_prefetch_common.cc",
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
#include <vector> #include <vector>
#include "base/base64.h" #include "base/base64.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/scoped_refptr.h" #include "base/memory/scoped_refptr.h"
#include "base/single_thread_task_runner.h" #include "base/single_thread_task_runner.h"
...@@ -19,6 +21,7 @@ ...@@ -19,6 +21,7 @@
#include "chrome/browser/predictors/preconnect_manager.h" #include "chrome/browser/predictors/preconnect_manager.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_commands.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h" #include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -56,14 +59,12 @@ const char kHtmlSubresourcesPath[] = "/predictors/html_subresources.html"; ...@@ -56,14 +59,12 @@ const char kHtmlSubresourcesPath[] = "/predictors/html_subresources.html";
const std::string kHtmlSubresourcesHosts[] = {"test.com", "baz.com", "foo.com", const std::string kHtmlSubresourcesHosts[] = {"test.com", "baz.com", "foo.com",
"bar.com"}; "bar.com"};
GURL GetURLWithReplacements(net::test_server::EmbeddedTestServer* server, std::string GetPathWithPortReplacement(const std::string& path, uint16_t port) {
const std::string& host, std::string string_port = base::StringPrintf("%d", port);
const std::string& path) {
std::string port = base::StringPrintf("%d", server->port());
std::string path_with_replacements; std::string path_with_replacements;
net::test_server::GetFilePathWithReplacements( net::test_server::GetFilePathWithReplacements(
path, {{"REPLACE_WITH_PORT", port}}, &path_with_replacements); path, {{"REPLACE_WITH_PORT", string_port}}, &path_with_replacements);
return server->GetURL(host, path_with_replacements); return path_with_replacements;
} }
GURL GetDataURLWithContent(const std::string& content) { GURL GetDataURLWithContent(const std::string& content) {
...@@ -275,14 +276,27 @@ class TestPreconnectManagerObserver : public PreconnectManager::Observer { ...@@ -275,14 +276,27 @@ class TestPreconnectManagerObserver : public PreconnectManager::Observer {
CheckForWaitingLoop(); CheckForWaitingLoop();
} }
void OnProxyLookupFinished(const GURL& url, bool success) override {
GURL origin = url.GetOrigin();
if (success)
successful_proxy_lookups_.insert(origin);
else
unsuccessful_proxy_lookups_.insert(origin);
CheckForWaitingLoop();
}
void WaitUntilHostLookedUp(const std::string& host) { void WaitUntilHostLookedUp(const std::string& host) {
base::RunLoop run_loop; wait_event_ = WaitEvent::kDns;
DCHECK(waiting_on_dns_.empty()); DCHECK(waiting_on_dns_.empty());
DCHECK(!dns_run_loop_);
dns_run_loop_ = &run_loop;
waiting_on_dns_ = host; waiting_on_dns_ = host;
CheckForWaitingLoop(); Wait();
run_loop.Run(); }
void WaitUntilProxyLookedUp(const GURL& url) {
wait_event_ = WaitEvent::kProxy;
DCHECK(waiting_on_proxy_.is_empty());
waiting_on_proxy_ = url;
Wait();
} }
bool HasOriginAttemptedToPreconnect(const GURL& origin) { bool HasOriginAttemptedToPreconnect(const GURL& origin) {
...@@ -295,26 +309,62 @@ class TestPreconnectManagerObserver : public PreconnectManager::Observer { ...@@ -295,26 +309,62 @@ class TestPreconnectManagerObserver : public PreconnectManager::Observer {
base::ContainsKey(unsuccessful_dns_lookups_, host); base::ContainsKey(unsuccessful_dns_lookups_, host);
} }
bool HostFound(const GURL& url) { bool HostFound(const std::string& host) {
return base::ContainsKey(successful_dns_lookups_, url.host()); return base::ContainsKey(successful_dns_lookups_, host);
}
bool HasProxyBeenLookedUp(const GURL& url) {
return base::ContainsKey(successful_proxy_lookups_, url.GetOrigin()) ||
base::ContainsKey(unsuccessful_proxy_lookups_, url.GetOrigin());
}
bool ProxyFound(const GURL& url) {
return base::ContainsKey(successful_proxy_lookups_, url.GetOrigin());
} }
private: private:
enum class WaitEvent { kNone, kDns, kProxy };
void Wait() {
base::RunLoop run_loop;
DCHECK(!run_loop_);
run_loop_ = &run_loop;
CheckForWaitingLoop();
run_loop.Run();
}
void CheckForWaitingLoop() { void CheckForWaitingLoop() {
if (waiting_on_dns_.empty()) switch (wait_event_) {
return; case WaitEvent::kNone:
if (!HasHostBeenLookedUp(waiting_on_dns_)) return;
return; case WaitEvent::kDns:
DCHECK(dns_run_loop_); if (!HasHostBeenLookedUp(waiting_on_dns_))
waiting_on_dns_ = std::string(); return;
dns_run_loop_->Quit(); waiting_on_dns_ = std::string();
dns_run_loop_ = nullptr; break;
case WaitEvent::kProxy:
if (!HasProxyBeenLookedUp(waiting_on_proxy_))
return;
waiting_on_proxy_ = GURL();
break;
}
DCHECK(run_loop_);
run_loop_->Quit();
run_loop_ = nullptr;
wait_event_ = WaitEvent::kNone;
} }
WaitEvent wait_event_ = WaitEvent::kNone;
base::RunLoop* run_loop_ = nullptr;
std::string waiting_on_dns_; std::string waiting_on_dns_;
base::RunLoop* dns_run_loop_ = nullptr;
std::set<std::string> successful_dns_lookups_; std::set<std::string> successful_dns_lookups_;
std::set<std::string> unsuccessful_dns_lookups_; std::set<std::string> unsuccessful_dns_lookups_;
GURL waiting_on_proxy_;
std::set<GURL> successful_proxy_lookups_;
std::set<GURL> unsuccessful_proxy_lookups_;
std::set<GURL> preconnect_url_attempts_; std::set<GURL> preconnect_url_attempts_;
}; };
...@@ -323,6 +373,11 @@ class LoadingPredictorBrowserTest : public InProcessBrowserTest { ...@@ -323,6 +373,11 @@ class LoadingPredictorBrowserTest : public InProcessBrowserTest {
LoadingPredictorBrowserTest() {} LoadingPredictorBrowserTest() {}
~LoadingPredictorBrowserTest() override {} ~LoadingPredictorBrowserTest() override {}
void SetUp() override {
ASSERT_TRUE(embedded_test_server()->InitializeAndListen());
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override { void SetUpOnMainThread() override {
host_resolver()->AddRule("*", "127.0.0.1"); host_resolver()->AddRule("*", "127.0.0.1");
...@@ -330,7 +385,7 @@ class LoadingPredictorBrowserTest : public InProcessBrowserTest { ...@@ -330,7 +385,7 @@ class LoadingPredictorBrowserTest : public InProcessBrowserTest {
connection_listener_ = connection_listener_ =
std::make_unique<ConnectionListener>(connection_tracker_.get()); std::make_unique<ConnectionListener>(connection_tracker_.get());
embedded_test_server()->SetConnectionListener(connection_listener_.get()); embedded_test_server()->SetConnectionListener(connection_listener_.get());
ASSERT_TRUE(embedded_test_server()->Start()); embedded_test_server()->StartAcceptingConnections();
loading_predictor_ = loading_predictor_ =
LoadingPredictorFactory::GetForProfile(browser()->profile()); LoadingPredictorFactory::GetForProfile(browser()->profile());
...@@ -483,8 +538,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -483,8 +538,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
PrepareForPageLoadWithoutPrediction) { PrepareForPageLoadWithoutPrediction) {
// Navigate the first time to fill the HTTP cache. // Navigate the first time to fill the HTTP cache.
GURL url = GetURLWithReplacements(embedded_test_server(), "test.com", GURL url = embedded_test_server()->GetURL(
kHtmlSubresourcesPath); "test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
ui_test_utils::NavigateToURL(browser(), url); ui_test_utils::NavigateToURL(browser(), url);
ResetNetworkState(); ResetNetworkState();
ResetPredictorState(); ResetPredictorState();
...@@ -495,7 +551,7 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -495,7 +551,7 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB, browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
preconnect_manager_observer()->WaitUntilHostLookedUp(url.host()); preconnect_manager_observer()->WaitUntilHostLookedUp(url.host());
EXPECT_TRUE(preconnect_manager_observer()->HostFound(url)); EXPECT_TRUE(preconnect_manager_observer()->HostFound(url.host()));
// We should preconnect only 2 sockets for the main frame host. // We should preconnect only 2 sockets for the main frame host.
const size_t expected_connections = 2; const size_t expected_connections = 2;
connection_tracker()->WaitForAcceptedConnections(expected_connections); connection_tracker()->WaitForAcceptedConnections(expected_connections);
...@@ -508,8 +564,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -508,8 +564,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
// Tests that the LoadingPredictor has a prediction for a host after navigating // Tests that the LoadingPredictor has a prediction for a host after navigating
// to it. // to it.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, LearnFromNavigation) { IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, LearnFromNavigation) {
GURL url = GetURLWithReplacements(embedded_test_server(), "test.com", GURL url = embedded_test_server()->GetURL(
kHtmlSubresourcesPath); "test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
std::vector<PreconnectRequest> requests; std::vector<PreconnectRequest> requests;
for (const auto& host : kHtmlSubresourcesHosts) for (const auto& host : kHtmlSubresourcesHosts)
requests.emplace_back(embedded_test_server()->GetURL(host, "/"), 1); requests.emplace_back(embedded_test_server()->GetURL(host, "/"), 1);
...@@ -527,8 +584,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, LearnFromNavigation) { ...@@ -527,8 +584,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, LearnFromNavigation) {
// redirect. // redirect.
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
LearnFromNavigationWithRedirect) { LearnFromNavigationWithRedirect) {
GURL redirect_url = GetURLWithReplacements(embedded_test_server(), "test.com", GURL redirect_url = embedded_test_server()->GetURL(
kHtmlSubresourcesPath); "test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
GURL original_url = embedded_test_server()->GetURL( GURL original_url = embedded_test_server()->GetURL(
"redirect.com", "redirect.com",
base::StringPrintf("/server-redirect?%s", redirect_url.spec().c_str())); base::StringPrintf("/server-redirect?%s", redirect_url.spec().c_str()));
...@@ -565,8 +623,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -565,8 +623,9 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
PrepareForPageLoadWithPrediction) { PrepareForPageLoadWithPrediction) {
// Navigate the first time to fill the predictor's database and the HTTP // Navigate the first time to fill the predictor's database and the HTTP
// cache. // cache.
GURL url = GetURLWithReplacements(embedded_test_server(), "test.com", GURL url = embedded_test_server()->GetURL(
kHtmlSubresourcesPath); "test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
ui_test_utils::NavigateToURL(browser(), url); ui_test_utils::NavigateToURL(browser(), url);
ResetNetworkState(); ResetNetworkState();
...@@ -578,7 +637,7 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -578,7 +637,7 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
for (const auto& host : kHtmlSubresourcesHosts) { for (const auto& host : kHtmlSubresourcesHosts) {
GURL url(base::StringPrintf("http://%s", host.c_str())); GURL url(base::StringPrintf("http://%s", host.c_str()));
preconnect_manager_observer()->WaitUntilHostLookedUp(url.host()); preconnect_manager_observer()->WaitUntilHostLookedUp(url.host());
EXPECT_TRUE(preconnect_manager_observer()->HostFound(url)); EXPECT_TRUE(preconnect_manager_observer()->HostFound(url.host()));
} }
// 2 connections to the main frame host + 1 connection per host for others. // 2 connections to the main frame host + 1 connection per host for others.
const size_t expected_connections = base::size(kHtmlSubresourcesHosts) + 1; const size_t expected_connections = base::size(kHtmlSubresourcesHosts) + 1;
...@@ -597,7 +656,8 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, DnsPrefetch) { ...@@ -597,7 +656,8 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, DnsPrefetch) {
GURL(kChromiumUrl).host()); GURL(kChromiumUrl).host());
EXPECT_FALSE(preconnect_manager_observer()->HasHostBeenLookedUp( EXPECT_FALSE(preconnect_manager_observer()->HasHostBeenLookedUp(
GURL(kInvalidLongUrl).host())); GURL(kInvalidLongUrl).host()));
EXPECT_TRUE(preconnect_manager_observer()->HostFound(GURL(kChromiumUrl))); EXPECT_TRUE(
preconnect_manager_observer()->HostFound(GURL(kChromiumUrl).host()));
} }
// Tests that preconnect warms up a socket connection to a test server. // Tests that preconnect warms up a socket connection to a test server.
...@@ -714,4 +774,88 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest, ...@@ -714,4 +774,88 @@ IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTest,
EXPECT_EQ(1u, connection_tracker()->GetReadSocketCount()); EXPECT_EQ(1u, connection_tracker()->GetReadSocketCount());
} }
class LoadingPredictorBrowserTestWithProxy
: public LoadingPredictorBrowserTest {
public:
void SetUp() override {
pac_script_server_ = std::make_unique<net::EmbeddedTestServer>();
pac_script_server_->AddDefaultHandlers(
base::FilePath(FILE_PATH_LITERAL("chrome/test/data")));
ASSERT_TRUE(pac_script_server_->InitializeAndListen());
LoadingPredictorBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
LoadingPredictorBrowserTest::SetUpOnMainThread();
// This will make all dns requests fail.
host_resolver()->ClearRules();
pac_script_server_->StartAcceptingConnections();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
GURL pac_url = pac_script_server_->GetURL(GetPathWithPortReplacement(
"/predictors/proxy.pac", embedded_test_server()->port()));
command_line->AppendSwitchASCII(switches::kProxyPacUrl, pac_url.spec());
}
private:
std::unique_ptr<net::EmbeddedTestServer> pac_script_server_;
};
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestWithProxy,
PrepareForPageLoadWithoutPrediction) {
// Navigate the first time to fill the HTTP cache.
GURL url = embedded_test_server()->GetURL(
"test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
ui_test_utils::NavigateToURL(browser(), url);
ResetNetworkState();
ResetPredictorState();
// Open in a new foreground tab to avoid being classified as a reload since
// reload requests are always revalidated.
ui_test_utils::NavigateToURLWithDisposition(
browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
preconnect_manager_observer()->WaitUntilProxyLookedUp(url);
EXPECT_TRUE(preconnect_manager_observer()->ProxyFound(url));
// We should preconnect only 2 sockets for the main frame host.
const size_t expected_connections = 2;
connection_tracker()->WaitForAcceptedConnections(expected_connections);
EXPECT_EQ(expected_connections,
connection_tracker()->GetAcceptedSocketCount());
// No reads since all resources should be cached.
EXPECT_EQ(0u, connection_tracker()->GetReadSocketCount());
}
IN_PROC_BROWSER_TEST_F(LoadingPredictorBrowserTestWithProxy,
PrepareForPageLoadWithPrediction) {
// Navigate the first time to fill the predictor's database and the HTTP
// cache.
GURL url = embedded_test_server()->GetURL(
"test.com", GetPathWithPortReplacement(kHtmlSubresourcesPath,
embedded_test_server()->port()));
ui_test_utils::NavigateToURL(browser(), url);
ResetNetworkState();
// Open in a new foreground tab to avoid being classified as a reload since
// reload requests are always revalidated.
ui_test_utils::NavigateToURLWithDisposition(
browser(), url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
for (const auto& host : kHtmlSubresourcesHosts) {
GURL url = embedded_test_server()->GetURL(host, "/");
preconnect_manager_observer()->WaitUntilProxyLookedUp(url);
EXPECT_TRUE(preconnect_manager_observer()->ProxyFound(url));
}
// 2 connections to the main frame host + 1 connection per host for others.
const size_t expected_connections = base::size(kHtmlSubresourcesHosts) + 1;
connection_tracker()->WaitForAcceptedConnections(expected_connections);
EXPECT_EQ(expected_connections,
connection_tracker()->GetAcceptedSocketCount());
// No reads since all resources should be cached.
EXPECT_EQ(0u, connection_tracker()->GetReadSocketCount());
}
} // namespace predictors } // namespace predictors
...@@ -174,11 +174,11 @@ TEST_F(LoadingStatsCollectorTest, TestPreconnectHistograms) { ...@@ -174,11 +174,11 @@ TEST_F(LoadingStatsCollectorTest, TestPreconnectHistograms) {
// Initialize PreconnectStats. // Initialize PreconnectStats.
// These two are hits. // These two are hits.
PreconnectedRequestStats origin1(GURL(gen(1)).GetOrigin(), false, true); PreconnectedRequestStats origin1(GURL(gen(1)).GetOrigin(), true);
PreconnectedRequestStats origin2(GURL(gen(2)).GetOrigin(), true, false); PreconnectedRequestStats origin2(GURL(gen(2)).GetOrigin(), false);
// And these two are misses. // And these two are misses.
PreconnectedRequestStats origin3(GURL(gen(3)).GetOrigin(), false, false); PreconnectedRequestStats origin3(GURL(gen(3)).GetOrigin(), false);
PreconnectedRequestStats origin4(GURL(gen(4)).GetOrigin(), true, true); PreconnectedRequestStats origin4(GURL(gen(4)).GetOrigin(), true);
auto stats = std::make_unique<PreconnectStats>(GURL(main_frame_url)); auto stats = std::make_unique<PreconnectStats>(GURL(main_frame_url));
stats->requests_stats = {origin1, origin2, origin3, origin4}; stats->requests_stats = {origin1, origin2, origin3, origin4};
...@@ -257,11 +257,11 @@ TEST_F(LoadingStatsCollectorTest, TestPreconnectHistogramsPreresolvesOnly) { ...@@ -257,11 +257,11 @@ TEST_F(LoadingStatsCollectorTest, TestPreconnectHistogramsPreresolvesOnly) {
// Initialize PreconnectStats. // Initialize PreconnectStats.
// These two are hits. // These two are hits.
PreconnectedRequestStats origin1(GURL(gen(1)).GetOrigin(), false, false); PreconnectedRequestStats origin1(GURL(gen(1)).GetOrigin(), false);
PreconnectedRequestStats origin2(GURL(gen(2)).GetOrigin(), true, false); PreconnectedRequestStats origin2(GURL(gen(2)).GetOrigin(), false);
// And these two are misses. // And these two are misses.
PreconnectedRequestStats origin3(GURL(gen(3)).GetOrigin(), false, false); PreconnectedRequestStats origin3(GURL(gen(3)).GetOrigin(), false);
PreconnectedRequestStats origin4(GURL(gen(4)).GetOrigin(), true, false); PreconnectedRequestStats origin4(GURL(gen(4)).GetOrigin(), false);
auto stats = std::make_unique<PreconnectStats>(GURL(main_frame_url)); auto stats = std::make_unique<PreconnectStats>(GURL(main_frame_url));
stats->requests_stats = {origin1, origin2, origin3, origin4}; stats->requests_stats = {origin1, origin2, origin3, origin4};
......
...@@ -19,10 +19,8 @@ namespace predictors { ...@@ -19,10 +19,8 @@ namespace predictors {
const bool kAllowCredentialsOnPreconnectByDefault = true; const bool kAllowCredentialsOnPreconnectByDefault = true;
PreconnectedRequestStats::PreconnectedRequestStats(const GURL& origin, PreconnectedRequestStats::PreconnectedRequestStats(const GURL& origin,
bool was_preresolve_cached,
bool was_preconnected) bool was_preconnected)
: origin(origin), : origin(origin),
was_preresolve_cached(was_preresolve_cached),
was_preconnected(was_preconnected) {} was_preconnected(was_preconnected) {}
PreconnectedRequestStats::PreconnectedRequestStats( PreconnectedRequestStats::PreconnectedRequestStats(
...@@ -141,7 +139,6 @@ void PreconnectManager::Stop(const GURL& url) { ...@@ -141,7 +139,6 @@ void PreconnectManager::Stop(const GURL& url) {
} }
void PreconnectManager::PreconnectUrl(const GURL& url, void PreconnectManager::PreconnectUrl(const GURL& url,
const GURL& site_for_cookies,
int num_sockets, int num_sockets,
bool allow_credentials) const { bool allow_credentials) const {
DCHECK(url.GetOrigin() == url); DCHECK(url.GetOrigin() == url);
...@@ -171,8 +168,6 @@ std::unique_ptr<ResolveHostClientImpl> PreconnectManager::PreresolveUrl( ...@@ -171,8 +168,6 @@ std::unique_ptr<ResolveHostClientImpl> PreconnectManager::PreresolveUrl(
ResolveHostCallback callback) const { ResolveHostCallback callback) const {
DCHECK(url.GetOrigin() == url); DCHECK(url.GetOrigin() == url);
DCHECK(url.SchemeIsHTTPOrHTTPS()); DCHECK(url.SchemeIsHTTPOrHTTPS());
if (observer_)
observer_->OnPreresolveUrl(url);
auto* network_context = GetNetworkContext(); auto* network_context = GetNetworkContext();
if (!network_context) { if (!network_context) {
...@@ -185,7 +180,24 @@ std::unique_ptr<ResolveHostClientImpl> PreconnectManager::PreresolveUrl( ...@@ -185,7 +180,24 @@ std::unique_ptr<ResolveHostClientImpl> PreconnectManager::PreresolveUrl(
} }
return std::make_unique<ResolveHostClientImpl>(url, std::move(callback), return std::make_unique<ResolveHostClientImpl>(url, std::move(callback),
GetNetworkContext()); network_context);
}
std::unique_ptr<ProxyLookupClientImpl> PreconnectManager::LookupProxyForUrl(
const GURL& url,
ProxyLookupCallback callback) const {
DCHECK(url.GetOrigin() == url);
DCHECK(url.SchemeIsHTTPOrHTTPS());
auto* network_context = GetNetworkContext();
if (!network_context) {
// It's okay to not invoke the callback here because PreresolveUrl()
// callback will be invoked.
return nullptr;
}
return std::make_unique<ProxyLookupClientImpl>(url, std::move(callback),
network_context);
} }
void PreconnectManager::TryToLaunchPreresolveJobs() { void PreconnectManager::TryToLaunchPreresolveJobs() {
...@@ -200,7 +212,13 @@ void PreconnectManager::TryToLaunchPreresolveJobs() { ...@@ -200,7 +212,13 @@ void PreconnectManager::TryToLaunchPreresolveJobs() {
PreresolveInfo* info = job->info; PreresolveInfo* info = job->info;
if (!(info && info->was_canceled)) { if (!(info && info->was_canceled)) {
// TODO(crbug.com/838763): Preconnect to url if proxy is enabled. // This is used to avoid issuing DNS requests when a fixed proxy
// configuration is in place, which improves efficiency, and is also
// important if the unproxied DNS may contain incorrect entries.
job->proxy_lookup_client = LookupProxyForUrl(
job->url, base::BindOnce(&PreconnectManager::OnProxyLookupFinished,
weak_factory_.GetWeakPtr(), job_id));
job->resolve_host_client = PreresolveUrl( job->resolve_host_client = PreresolveUrl(
job->url, base::BindOnce(&PreconnectManager::OnPreresolveFinished, job->url, base::BindOnce(&PreconnectManager::OnPreresolveFinished,
weak_factory_.GetWeakPtr(), job_id)); weak_factory_.GetWeakPtr(), job_id));
...@@ -221,37 +239,52 @@ void PreconnectManager::OnPreresolveFinished(PreresolveJobId job_id, ...@@ -221,37 +239,52 @@ void PreconnectManager::OnPreresolveFinished(PreresolveJobId job_id,
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PreresolveJob* job = preresolve_jobs_.Lookup(job_id); PreresolveJob* job = preresolve_jobs_.Lookup(job_id);
DCHECK(job); DCHECK(job);
PreresolveInfo* info = job->info;
if (observer_) if (observer_)
observer_->OnPreresolveFinished(job->url, success); observer_->OnPreresolveFinished(job->url, success);
FinishPreresolve(job_id, success, false); job->resolve_host_client = nullptr;
--inflight_preresolves_count_; FinishPreresolveJob(job_id, success);
if (info)
--info->inflight_count;
if (info && info->is_done())
AllPreresolvesForUrlFinished(info);
TryToLaunchPreresolveJobs();
} }
void PreconnectManager::FinishPreresolve(PreresolveJobId job_id, void PreconnectManager::OnProxyLookupFinished(PreresolveJobId job_id,
bool found, bool success) {
bool cached) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PreresolveJob* job = preresolve_jobs_.Lookup(job_id); PreresolveJob* job = preresolve_jobs_.Lookup(job_id);
DCHECK(job); DCHECK(job);
PreresolveInfo* info = job->info;
bool need_preconnect = if (observer_)
found && job->need_preconnect() && (!info || !info->was_canceled); observer_->OnProxyLookupFinished(job->url, success);
if (need_preconnect) {
PreconnectUrl(job->url, info ? info->url : GURL(), job->num_sockets, job->proxy_lookup_client = nullptr;
job->allow_credentials); FinishPreresolveJob(job_id, success);
} }
if (info && found)
info->stats->requests_stats.emplace_back(job->url, cached, need_preconnect); void PreconnectManager::FinishPreresolveJob(PreresolveJobId job_id,
bool success) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PreresolveJob* job = preresolve_jobs_.Lookup(job_id);
DCHECK(job);
// In case one of the clients failed, wait for the second one, because it may
// be successful.
if (!success && (job->resolve_host_client || job->proxy_lookup_client))
return;
bool need_preconnect = success && job->need_preconnect();
if (need_preconnect)
PreconnectUrl(job->url, job->num_sockets, job->allow_credentials);
PreresolveInfo* info = job->info;
if (info)
info->stats->requests_stats.emplace_back(job->url, need_preconnect);
preresolve_jobs_.Remove(job_id); preresolve_jobs_.Remove(job_id);
--inflight_preresolves_count_;
if (info)
--info->inflight_count;
if (info && info->is_done())
AllPreresolvesForUrlFinished(info);
TryToLaunchPreresolveJobs();
} }
void PreconnectManager::AllPreresolvesForUrlFinished(PreresolveInfo* info) { void PreconnectManager::AllPreresolvesForUrlFinished(PreresolveInfo* info) {
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/containers/id_map.h" #include "base/containers/id_map.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/predictors/proxy_lookup_client_impl.h"
#include "chrome/browser/predictors/resolve_host_client_impl.h" #include "chrome/browser/predictors/resolve_host_client_impl.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h" #include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "url/gurl.h" #include "url/gurl.h"
...@@ -32,13 +33,11 @@ struct PreconnectRequest; ...@@ -32,13 +33,11 @@ struct PreconnectRequest;
struct PreconnectedRequestStats { struct PreconnectedRequestStats {
PreconnectedRequestStats(const GURL& origin, PreconnectedRequestStats(const GURL& origin,
bool was_preresolve_cached,
bool was_preconnected); bool was_preconnected);
PreconnectedRequestStats(const PreconnectedRequestStats& other); PreconnectedRequestStats(const PreconnectedRequestStats& other);
~PreconnectedRequestStats(); ~PreconnectedRequestStats();
GURL origin; GURL origin;
bool was_preresolve_cached;
bool was_preconnected; bool was_preconnected;
}; };
...@@ -79,7 +78,9 @@ struct PreresolveJob { ...@@ -79,7 +78,9 @@ struct PreresolveJob {
PreresolveInfo* info); PreresolveInfo* info);
PreresolveJob(PreresolveJob&& other); PreresolveJob(PreresolveJob&& other);
~PreresolveJob(); ~PreresolveJob();
bool need_preconnect() const { return num_sockets > 0; } bool need_preconnect() const {
return num_sockets > 0 && !(info && info->was_canceled);
}
GURL url; GURL url;
int num_sockets; int num_sockets;
...@@ -90,6 +91,7 @@ struct PreresolveJob { ...@@ -90,6 +91,7 @@ struct PreresolveJob {
// May be equal to nullptr in case of detached job. // May be equal to nullptr in case of detached job.
PreresolveInfo* info; PreresolveInfo* info;
std::unique_ptr<ResolveHostClientImpl> resolve_host_client; std::unique_ptr<ResolveHostClientImpl> resolve_host_client;
std::unique_ptr<ProxyLookupClientImpl> proxy_lookup_client;
DISALLOW_COPY_AND_ASSIGN(PreresolveJob); DISALLOW_COPY_AND_ASSIGN(PreresolveJob);
}; };
...@@ -125,9 +127,9 @@ class PreconnectManager { ...@@ -125,9 +127,9 @@ class PreconnectManager {
virtual void OnPreconnectUrl(const GURL& url, virtual void OnPreconnectUrl(const GURL& url,
int num_sockets, int num_sockets,
bool allow_credentials) {} bool allow_credentials) {}
virtual void OnPreresolveUrl(const GURL& url) {}
virtual void OnPreresolveFinished(const GURL& url, bool success) {} virtual void OnPreresolveFinished(const GURL& url, bool success) {}
virtual void OnProxyLookupFinished(const GURL& url, bool success) {}
}; };
static const size_t kMaxInflightPreresolves = 3; static const size_t kMaxInflightPreresolves = 3;
...@@ -165,16 +167,19 @@ class PreconnectManager { ...@@ -165,16 +167,19 @@ class PreconnectManager {
friend class PreconnectManagerTest; friend class PreconnectManagerTest;
void PreconnectUrl(const GURL& url, void PreconnectUrl(const GURL& url,
const GURL& site_for_cookies,
int num_sockets, int num_sockets,
bool allow_credentials) const; bool allow_credentials) const;
std::unique_ptr<ResolveHostClientImpl> PreresolveUrl( std::unique_ptr<ResolveHostClientImpl> PreresolveUrl(
const GURL& url, const GURL& url,
ResolveHostCallback callback) const; ResolveHostCallback callback) const;
std::unique_ptr<ProxyLookupClientImpl> LookupProxyForUrl(
const GURL& url,
ProxyLookupCallback callback) const;
void TryToLaunchPreresolveJobs(); void TryToLaunchPreresolveJobs();
void OnPreresolveFinished(PreresolveJobId job_id, bool success); void OnPreresolveFinished(PreresolveJobId job_id, bool success);
void FinishPreresolve(PreresolveJobId job_id, bool found, bool cached); void OnProxyLookupFinished(PreresolveJobId job_id, bool success);
void FinishPreresolveJob(PreresolveJobId job_id, bool success);
void AllPreresolvesForUrlFinished(PreresolveInfo* info); void AllPreresolvesForUrlFinished(PreresolveInfo* info);
network::mojom::NetworkContext* GetNetworkContext() const; network::mojom::NetworkContext* GetNetworkContext() const;
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/predictors/loading_test_util.h" #include "chrome/browser/predictors/loading_test_util.h"
#include "chrome/browser/predictors/proxy_lookup_client_impl.h"
#include "chrome/browser/predictors/resolve_host_client_impl.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
...@@ -34,6 +36,18 @@ constexpr int kPrivateLoadFlags = net::LOAD_DO_NOT_SEND_COOKIES | ...@@ -34,6 +36,18 @@ constexpr int kPrivateLoadFlags = net::LOAD_DO_NOT_SEND_COOKIES |
net::LOAD_DO_NOT_SAVE_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DO_NOT_SEND_AUTH_DATA; net::LOAD_DO_NOT_SEND_AUTH_DATA;
net::ProxyInfo GetIndirectProxyInfo() {
net::ProxyInfo proxy_info;
proxy_info.UseNamedProxy("proxy.com");
return proxy_info;
}
net::ProxyInfo GetDirectProxyInfo() {
net::ProxyInfo proxy_info;
proxy_info.UseDirect();
return proxy_info;
}
class MockPreconnectManagerDelegate class MockPreconnectManagerDelegate
: public PreconnectManager::Delegate, : public PreconnectManager::Delegate,
public base::SupportsWeakPtr<MockPreconnectManagerDelegate> { public base::SupportsWeakPtr<MockPreconnectManagerDelegate> {
...@@ -51,12 +65,12 @@ class MockNetworkContext : public network::TestNetworkContext { ...@@ -51,12 +65,12 @@ class MockNetworkContext : public network::TestNetworkContext {
MockNetworkContext() = default; MockNetworkContext() = default;
~MockNetworkContext() override { ~MockNetworkContext() override {
EXPECT_TRUE(resolve_host_clients_.empty()) EXPECT_TRUE(resolve_host_clients_.empty())
<< "Not all requests were satisfied"; << "Not all resolve host requests were satisfied";
}; };
void ResolveHost( void ResolveHost(
const net::HostPortPair& host_port, const net::HostPortPair& host_port,
network::mojom::ResolveHostParametersPtr control_handle, network::mojom::ResolveHostParametersPtr optional_parameters,
network::mojom::ResolveHostClientPtr response_client) override { network::mojom::ResolveHostClientPtr response_client) override {
const std::string& host = host_port.host(); const std::string& host = host_port.host();
EXPECT_TRUE( EXPECT_TRUE(
...@@ -64,7 +78,15 @@ class MockNetworkContext : public network::TestNetworkContext { ...@@ -64,7 +78,15 @@ class MockNetworkContext : public network::TestNetworkContext {
ResolveHostProxy(host); ResolveHostProxy(host);
} }
void CompleteRequest(const std::string& host, int result) { void LookUpProxyForURL(
const GURL& url,
network::mojom::ProxyLookupClientPtr proxy_lookup_client) override {
EXPECT_TRUE(
proxy_lookup_clients_.emplace(url, std::move(proxy_lookup_client))
.second);
}
void CompleteHostLookup(const std::string& host, int result) {
auto it = resolve_host_clients_.find(host); auto it = resolve_host_clients_.find(host);
if (it == resolve_host_clients_.end()) { if (it == resolve_host_clients_.end()) {
ADD_FAILURE() << host << " wasn't found"; ADD_FAILURE() << host << " wasn't found";
...@@ -76,6 +98,19 @@ class MockNetworkContext : public network::TestNetworkContext { ...@@ -76,6 +98,19 @@ class MockNetworkContext : public network::TestNetworkContext {
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
} }
void CompleteProxyLookup(const GURL& url,
const base::Optional<net::ProxyInfo>& result) {
auto it = proxy_lookup_clients_.find(url);
if (it == proxy_lookup_clients_.end()) {
ADD_FAILURE() << url.spec() << " wasn't found";
return;
}
it->second->OnProxyLookupComplete(result);
proxy_lookup_clients_.erase(it);
// Wait for OnProxyLookupComplete() to be executed on the UI thread.
base::RunLoop().RunUntilIdle();
}
MOCK_METHOD1(ResolveHostProxy, void(const std::string& host)); MOCK_METHOD1(ResolveHostProxy, void(const std::string& host));
MOCK_METHOD4(PreconnectSockets, MOCK_METHOD4(PreconnectSockets,
void(uint32_t num_streams, void(uint32_t num_streams,
...@@ -86,6 +121,7 @@ class MockNetworkContext : public network::TestNetworkContext { ...@@ -86,6 +121,7 @@ class MockNetworkContext : public network::TestNetworkContext {
private: private:
std::map<std::string, network::mojom::ResolveHostClientPtr> std::map<std::string, network::mojom::ResolveHostClientPtr>
resolve_host_clients_; resolve_host_clients_;
std::map<GURL, network::mojom::ProxyLookupClientPtr> proxy_lookup_clients_;
}; };
class PreconnectManagerTest : public testing::Test { class PreconnectManagerTest : public testing::Test {
...@@ -126,7 +162,7 @@ TEST_F(PreconnectManagerTest, TestStartOneUrlPreresolve) { ...@@ -126,7 +162,7 @@ TEST_F(PreconnectManagerTest, TestStartOneUrlPreresolve) {
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
preconnect_manager_->Start(main_frame_url, preconnect_manager_->Start(main_frame_url,
{PreconnectRequest(url_to_preresolve, 0)}); {PreconnectRequest(url_to_preresolve, 0)});
mock_network_context_->CompleteRequest(url_to_preresolve.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preresolve.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestStartOneUrlPreconnect) { TEST_F(PreconnectManagerTest, TestStartOneUrlPreconnect) {
...@@ -140,7 +176,7 @@ TEST_F(PreconnectManagerTest, TestStartOneUrlPreconnect) { ...@@ -140,7 +176,7 @@ TEST_F(PreconnectManagerTest, TestStartOneUrlPreconnect) {
EXPECT_CALL(*mock_network_context_, EXPECT_CALL(*mock_network_context_,
PreconnectSockets(1, url_to_preconnect, kNormalLoadFlags, false)); PreconnectSockets(1, url_to_preconnect, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteRequest(url_to_preconnect.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestStopOneUrlBeforePreconnect) { TEST_F(PreconnectManagerTest, TestStopOneUrlBeforePreconnect) {
...@@ -156,7 +192,7 @@ TEST_F(PreconnectManagerTest, TestStopOneUrlBeforePreconnect) { ...@@ -156,7 +192,7 @@ TEST_F(PreconnectManagerTest, TestStopOneUrlBeforePreconnect) {
// Stop all jobs for |main_frame_url| before we get the callback. // Stop all jobs for |main_frame_url| before we get the callback.
preconnect_manager_->Stop(main_frame_url); preconnect_manager_->Stop(main_frame_url);
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteRequest(url_to_preconnect.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestGetCallbackAfterDestruction) { TEST_F(PreconnectManagerTest, TestGetCallbackAfterDestruction) {
...@@ -169,7 +205,7 @@ TEST_F(PreconnectManagerTest, TestGetCallbackAfterDestruction) { ...@@ -169,7 +205,7 @@ TEST_F(PreconnectManagerTest, TestGetCallbackAfterDestruction) {
// Callback may outlive PreconnectManager but it shouldn't cause a crash. // Callback may outlive PreconnectManager but it shouldn't cause a crash.
preconnect_manager_ = nullptr; preconnect_manager_ = nullptr;
mock_network_context_->CompleteRequest(url_to_preconnect.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) { TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) {
...@@ -190,7 +226,8 @@ TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) { ...@@ -190,7 +226,8 @@ TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) {
preconnect_manager_->Stop(main_frame_url); preconnect_manager_->Stop(main_frame_url);
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
for (size_t i = 0; i < count; ++i) for (size_t i = 0; i < count; ++i)
mock_network_context_->CompleteRequest(requests[i].origin.host(), net::OK); mock_network_context_->CompleteHostLookup(requests[i].origin.host(),
net::OK);
} }
TEST_F(PreconnectManagerTest, TestTwoConcurrentMainFrameUrls) { TEST_F(PreconnectManagerTest, TestTwoConcurrentMainFrameUrls) {
...@@ -216,10 +253,10 @@ TEST_F(PreconnectManagerTest, TestTwoConcurrentMainFrameUrls) { ...@@ -216,10 +253,10 @@ TEST_F(PreconnectManagerTest, TestTwoConcurrentMainFrameUrls) {
*mock_network_context_, *mock_network_context_,
PreconnectSockets(1, url_to_preconnect1, kNormalLoadFlags, false)); PreconnectSockets(1, url_to_preconnect1, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1));
mock_network_context_->CompleteRequest(url_to_preconnect1.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect1.host(), net::OK);
// No preconnect for the second url. // No preconnect for the second url.
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url2)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url2));
mock_network_context_->CompleteRequest(url_to_preconnect2.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect2.host(), net::OK);
} }
// Checks that the PreconnectManager handles no more than one URL per host // Checks that the PreconnectManager handles no more than one URL per host
...@@ -243,7 +280,7 @@ TEST_F(PreconnectManagerTest, TestTwoConcurrentSameHostMainFrameUrls) { ...@@ -243,7 +280,7 @@ TEST_F(PreconnectManagerTest, TestTwoConcurrentSameHostMainFrameUrls) {
*mock_network_context_, *mock_network_context_,
PreconnectSockets(1, url_to_preconnect1, kNormalLoadFlags, false)); PreconnectSockets(1, url_to_preconnect1, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url1));
mock_network_context_->CompleteRequest(url_to_preconnect1.host(), net::OK); mock_network_context_->CompleteHostLookup(url_to_preconnect1.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestStartPreresolveHost) { TEST_F(PreconnectManagerTest, TestStartPreresolveHost) {
...@@ -253,7 +290,7 @@ TEST_F(PreconnectManagerTest, TestStartPreresolveHost) { ...@@ -253,7 +290,7 @@ TEST_F(PreconnectManagerTest, TestStartPreresolveHost) {
// PreconnectFinished shouldn't be called. // PreconnectFinished shouldn't be called.
EXPECT_CALL(*mock_network_context_, ResolveHostProxy(origin.host())); EXPECT_CALL(*mock_network_context_, ResolveHostProxy(origin.host()));
preconnect_manager_->StartPreresolveHost(url); preconnect_manager_->StartPreresolveHost(url);
mock_network_context_->CompleteRequest(origin.host(), net::OK); mock_network_context_->CompleteHostLookup(origin.host(), net::OK);
// Non http url shouldn't be preresovled. // Non http url shouldn't be preresovled.
GURL non_http_url("file:///tmp/index.html"); GURL non_http_url("file:///tmp/index.html");
...@@ -267,8 +304,8 @@ TEST_F(PreconnectManagerTest, TestStartPreresolveHosts) { ...@@ -267,8 +304,8 @@ TEST_F(PreconnectManagerTest, TestStartPreresolveHosts) {
EXPECT_CALL(*mock_network_context_, ResolveHostProxy(cdn.host())); EXPECT_CALL(*mock_network_context_, ResolveHostProxy(cdn.host()));
EXPECT_CALL(*mock_network_context_, ResolveHostProxy(fonts.host())); EXPECT_CALL(*mock_network_context_, ResolveHostProxy(fonts.host()));
preconnect_manager_->StartPreresolveHosts({cdn.host(), fonts.host()}); preconnect_manager_->StartPreresolveHosts({cdn.host(), fonts.host()});
mock_network_context_->CompleteRequest(cdn.host(), net::OK); mock_network_context_->CompleteHostLookup(cdn.host(), net::OK);
mock_network_context_->CompleteRequest(fonts.host(), net::OK); mock_network_context_->CompleteHostLookup(fonts.host(), net::OK);
} }
TEST_F(PreconnectManagerTest, TestStartPreconnectUrl) { TEST_F(PreconnectManagerTest, TestStartPreconnectUrl) {
...@@ -282,7 +319,7 @@ TEST_F(PreconnectManagerTest, TestStartPreconnectUrl) { ...@@ -282,7 +319,7 @@ TEST_F(PreconnectManagerTest, TestStartPreconnectUrl) {
EXPECT_CALL( EXPECT_CALL(
*mock_network_context_, *mock_network_context_,
PreconnectSockets(1, origin, kPrivateLoadFlags, !allow_credentials)); PreconnectSockets(1, origin, kPrivateLoadFlags, !allow_credentials));
mock_network_context_->CompleteRequest(origin.host(), net::OK); mock_network_context_->CompleteHostLookup(origin.host(), net::OK);
// Non http url shouldn't be preconnected. // Non http url shouldn't be preconnected.
GURL non_http_url("file:///tmp/index.html"); GURL non_http_url("file:///tmp/index.html");
...@@ -312,16 +349,112 @@ TEST_F(PreconnectManagerTest, TestDetachedRequestHasHigherPriority) { ...@@ -312,16 +349,112 @@ TEST_F(PreconnectManagerTest, TestDetachedRequestHasHigherPriority) {
EXPECT_CALL(*mock_network_context_, EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(detached_preresolve.host())); ResolveHostProxy(detached_preresolve.host()));
mock_network_context_->CompleteRequest(requests[0].origin.host(), net::OK); mock_network_context_->CompleteHostLookup(requests[0].origin.host(), net::OK);
Mock::VerifyAndClearExpectations(preconnect_manager_.get()); Mock::VerifyAndClearExpectations(preconnect_manager_.get());
EXPECT_CALL(*mock_network_context_, ResolveHostProxy(queued_url.host())); EXPECT_CALL(*mock_network_context_, ResolveHostProxy(queued_url.host()));
mock_network_context_->CompleteRequest(detached_preresolve.host(), net::OK); mock_network_context_->CompleteHostLookup(detached_preresolve.host(),
mock_network_context_->CompleteRequest(queued_url.host(), net::OK); net::OK);
mock_network_context_->CompleteHostLookup(queued_url.host(), net::OK);
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url)); EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
for (size_t i = 1; i < count; ++i) for (size_t i = 1; i < count; ++i)
mock_network_context_->CompleteRequest(requests[i].origin.host(), net::OK); mock_network_context_->CompleteHostLookup(requests[i].origin.host(),
net::OK);
}
TEST_F(PreconnectManagerTest, TestSuccessfulProxyLookup) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect.host()));
preconnect_manager_->Start(main_frame_url,
{PreconnectRequest(url_to_preconnect, 1)});
EXPECT_CALL(*mock_network_context_,
PreconnectSockets(1, url_to_preconnect, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteProxyLookup(url_to_preconnect,
GetIndirectProxyInfo());
// We should preconnect socket before the host lookup is complete.
Mock::VerifyAndClearExpectations(mock_network_context_.get());
mock_network_context_->CompleteHostLookup(url_to_preconnect.host(), net::OK);
}
TEST_F(PreconnectManagerTest, TestSuccessfulProxyLookupAfterPreresolveFailure) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect.host()));
preconnect_manager_->Start(main_frame_url,
{PreconnectRequest(url_to_preconnect, 1)});
mock_network_context_->CompleteHostLookup(url_to_preconnect.host(),
net::ERR_FAILED);
Mock::VerifyAndClearExpectations(mock_network_context_.get());
EXPECT_CALL(*mock_network_context_,
PreconnectSockets(1, url_to_preconnect, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteProxyLookup(url_to_preconnect,
GetIndirectProxyInfo());
}
TEST_F(PreconnectManagerTest, TestSuccessfulHostLookupAfterProxyLookupFailure) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
GURL url_to_preconnect2("http://ads.google.com");
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect.host()));
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect2.host()));
preconnect_manager_->Start(main_frame_url,
{PreconnectRequest(url_to_preconnect, 1),
PreconnectRequest(url_to_preconnect2, 1)});
// First URL uses direct connection.
mock_network_context_->CompleteProxyLookup(url_to_preconnect,
GetDirectProxyInfo());
// Second URL proxy lookup failed.
mock_network_context_->CompleteProxyLookup(url_to_preconnect2, base::nullopt);
Mock::VerifyAndClearExpectations(mock_network_context_.get());
EXPECT_CALL(*mock_network_context_,
PreconnectSockets(1, url_to_preconnect, kNormalLoadFlags, false));
EXPECT_CALL(
*mock_network_context_,
PreconnectSockets(1, url_to_preconnect2, kNormalLoadFlags, false));
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteHostLookup(url_to_preconnect.host(), net::OK);
mock_network_context_->CompleteHostLookup(url_to_preconnect2.host(), net::OK);
}
TEST_F(PreconnectManagerTest, TestBothProxyAndHostLookupFailed) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
GURL url_to_preconnect2("http://ads.google.com");
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect.host()));
EXPECT_CALL(*mock_network_context_,
ResolveHostProxy(url_to_preconnect2.host()));
preconnect_manager_->Start(main_frame_url,
{PreconnectRequest(url_to_preconnect, 1),
PreconnectRequest(url_to_preconnect2, 1)});
// Test two failures in different order:
// proxy -> host for |url_to_preconnect|
// host -> proxy for |url_to_preconnect2|
mock_network_context_->CompleteProxyLookup(url_to_preconnect, base::nullopt);
mock_network_context_->CompleteHostLookup(url_to_preconnect2.host(),
net::ERR_FAILED);
Mock::VerifyAndClearExpectations(mock_network_context_.get());
EXPECT_CALL(*mock_delegate_, PreconnectFinishedProxy(main_frame_url));
mock_network_context_->CompleteHostLookup(url_to_preconnect.host(),
net::ERR_FAILED);
mock_network_context_->CompleteProxyLookup(url_to_preconnect2, base::nullopt);
} }
} // namespace predictors } // namespace predictors
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/predictors/proxy_lookup_client_impl.h"
#include <utility>
#include "base/bind.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "net/proxy_resolution/proxy_info.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "url/gurl.h"
namespace predictors {
ProxyLookupClientImpl::ProxyLookupClientImpl(
const GURL& url,
ProxyLookupCallback callback,
network::mojom::NetworkContext* network_context)
: binding_(this), callback_(std::move(callback)) {
network::mojom::ProxyLookupClientPtr proxy_lookup_client_ptr;
binding_.Bind(mojo::MakeRequest(&proxy_lookup_client_ptr));
network_context->LookUpProxyForURL(url, std::move(proxy_lookup_client_ptr));
binding_.set_connection_error_handler(
base::BindOnce(&ProxyLookupClientImpl::OnProxyLookupComplete,
base::Unretained(this), base::nullopt));
}
ProxyLookupClientImpl::~ProxyLookupClientImpl() = default;
void ProxyLookupClientImpl::OnProxyLookupComplete(
const base::Optional<net::ProxyInfo>& proxy_info) {
bool success = proxy_info.has_value() && !proxy_info->is_direct();
std::move(callback_).Run(success);
}
} // namespace predictors
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PREDICTORS_PROXY_LOOKUP_CLIENT_IMPL_H_
#define CHROME_BROWSER_PREDICTORS_PROXY_LOOKUP_CLIENT_IMPL_H_
#include "base/bind.h"
#include "base/macros.h"
#include "base/optional.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/network/public/mojom/proxy_lookup_client.mojom.h"
class GURL;
namespace network {
namespace mojom {
class NetworkContext;
}
} // namespace network
namespace predictors {
using ProxyLookupCallback = base::OnceCallback<void(bool success)>;
// This class helps perform the proxy lookup using the NetworkContext.
// An instance of this class must be deleted after the callback is invoked.
class ProxyLookupClientImpl : public network::mojom::ProxyLookupClient {
public:
// Starts the proxy lookup for |url|. |callback| is called when the proxy
// lookup is completed or when an error occurs.
ProxyLookupClientImpl(const GURL& url,
ProxyLookupCallback callback,
network::mojom::NetworkContext* network_context);
// Cancels the request if it hasn't been completed yet.
~ProxyLookupClientImpl() override;
// network::mojom::ProxyLookupClient:
void OnProxyLookupComplete(
const base::Optional<net::ProxyInfo>& proxy_info) override;
private:
mojo::Binding<network::mojom::ProxyLookupClient> binding_;
ProxyLookupCallback callback_;
DISALLOW_COPY_AND_ASSIGN(ProxyLookupClientImpl);
};
} // namespace predictors
#endif // CHROME_BROWSER_PREDICTORS_PROXY_LOOKUP_CLIENT_IMPL_H_
function FindProxyForURL(url, host)
{
if (shExpMatch(host, "test.com|foo.com|baz.com|bar.com"))
{
return "PROXY 127.0.0.1:REPLACE_WITH_PORT";
}
// All other requests don't need a proxy:
return "DIRECT";
}
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