Commit ae6f5b07 authored by Alexandr Ilin's avatar Alexandr Ilin Committed by Commit Bot

predictors: Implement PreconnectManager

This CL adds an implementation for PreconnectManager class together with tests.
PreconnectManager is responsible for preresolving and preconnecting to 
origins based on the input list of URLs.

Other changes:
- Modification of argument type of methods content::{Preconnect,Preresolve}Url
  from context::ResourceContext* to net::URLRequestContextGetter*.
- Adding missing LoadingPredictor::Shutdown() call in unittests + DCHECK that
  Shutdown() was actually called.

Bug: 699080
Change-Id: I5c6a303e5d22c9027da59b266a7537194b286c0b
Reviewed-on: https://chromium-review.googlesource.com/567189
Commit-Queue: Alexandr Ilin <alexilin@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarBenoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#487107}
parent dc2134dd
...@@ -92,8 +92,8 @@ void AuthPrewarmer::DoPrewarm() { ...@@ -92,8 +92,8 @@ void AuthPrewarmer::DoPrewarm() {
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&content::PreconnectUrl, base::BindOnce(&content::PreconnectUrl,
ProfileHelper::GetSigninProfile()->GetResourceContext(), base::RetainedRef(GetRequestContext()), url, url,
url, url, kConnectionsNeeded, true, kConnectionsNeeded, true,
net::HttpRequestInfo::EARLY_LOAD_MOTIVATED)); net::HttpRequestInfo::EARLY_LOAD_MOTIVATED));
if (!completion_callback_.is_null()) { if (!completion_callback_.is_null()) {
content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
......
...@@ -799,14 +799,15 @@ void Predictor::PreconnectUrlOnIOThread( ...@@ -799,14 +799,15 @@ void Predictor::PreconnectUrlOnIOThread(
GURL url = GetHSTSRedirectOnIOThread(original_url); GURL url = GetHSTSRedirectOnIOThread(original_url);
// TODO(csharrison): The observer should only be notified after the null check // TODO(csharrison): The observer should only be notified after the null check
// for the ProfileIOData. The predictor tests should be fixed to allow for // for the URLRequestContextGetter. The predictor tests should be fixed to
// this, as they currently expect a callback with no getter. // allow for this, as they currently expect a callback with no getter.
if (observer_) { if (observer_) {
observer_->OnPreconnectUrl( observer_->OnPreconnectUrl(
url, first_party_for_cookies, motivation, count); url, first_party_for_cookies, motivation, count);
} }
if (!profile_io_data_) net::URLRequestContextGetter* getter = url_request_context_getter_.get();
if (!getter)
return; return;
// Translate the motivation from UrlRequest motivations to HttpRequest // Translate the motivation from UrlRequest motivations to HttpRequest
...@@ -832,9 +833,8 @@ void Predictor::PreconnectUrlOnIOThread( ...@@ -832,9 +833,8 @@ void Predictor::PreconnectUrlOnIOThread(
} }
UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation, UMA_HISTOGRAM_ENUMERATION("Net.PreconnectMotivation", motivation,
UrlInfo::MAX_MOTIVATED); UrlInfo::MAX_MOTIVATED);
content::PreconnectUrl(profile_io_data_->GetResourceContext(), url, content::PreconnectUrl(getter, url, first_party_for_cookies, count,
first_party_for_cookies, count, allow_credentials, allow_credentials, request_motivation);
request_motivation);
} }
void Predictor::PredictFrameSubresources(const GURL& url, void Predictor::PredictFrameSubresources(const GURL& url,
...@@ -1056,7 +1056,7 @@ void Predictor::StartSomeQueuedResolutions() { ...@@ -1056,7 +1056,7 @@ void Predictor::StartSomeQueuedResolutions() {
} }
int status = int status =
content::PreresolveUrl(profile_io_data_->GetResourceContext(), url, content::PreresolveUrl(url_request_context_getter_.get(), url,
base::Bind(&Predictor::OnLookupFinished, base::Bind(&Predictor::OnLookupFinished,
io_weak_factory_->GetWeakPtr(), url)); io_weak_factory_->GetWeakPtr(), url));
if (status == net::ERR_IO_PENDING) { if (status == net::ERR_IO_PENDING) {
......
...@@ -35,7 +35,10 @@ LoadingPredictor::LoadingPredictor(const LoadingPredictorConfig& config, ...@@ -35,7 +35,10 @@ LoadingPredictor::LoadingPredictor(const LoadingPredictorConfig& config,
GetWeakPtr(), profile_->GetRequestContext()); GetWeakPtr(), profile_->GetRequestContext());
} }
LoadingPredictor::~LoadingPredictor() = default; LoadingPredictor::~LoadingPredictor() {
// Ensure that Shutdown() was called.
DCHECK(preconnect_manager_ == nullptr);
}
void LoadingPredictor::PrepareForPageLoad(const GURL& url, HintOrigin origin) { void LoadingPredictor::PrepareForPageLoad(const GURL& url, HintOrigin origin) {
if (active_hints_.find(url) != active_hints_.end()) if (active_hints_.find(url) != active_hints_.end())
...@@ -288,6 +291,7 @@ void LoadingPredictor::MaybeRemovePreconnect(const GURL& url) { ...@@ -288,6 +291,7 @@ void LoadingPredictor::MaybeRemovePreconnect(const GURL& url) {
} }
void LoadingPredictor::PreconnectFinished(const GURL& url) { void LoadingPredictor::PreconnectFinished(const GURL& url) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
......
...@@ -47,10 +47,7 @@ class LoadingPredictorTest : public testing::Test { ...@@ -47,10 +47,7 @@ class LoadingPredictorTest : public testing::Test {
LoadingPredictorTest::LoadingPredictorTest() LoadingPredictorTest::LoadingPredictorTest()
: profile_(base::MakeUnique<TestingProfile>()) {} : profile_(base::MakeUnique<TestingProfile>()) {}
LoadingPredictorTest::~LoadingPredictorTest() { LoadingPredictorTest::~LoadingPredictorTest() = default;
profile_ = nullptr;
base::RunLoop().RunUntilIdle();
}
void LoadingPredictorTest::SetUp() { void LoadingPredictorTest::SetUp() {
LoadingPredictorConfig config; LoadingPredictorConfig config;
...@@ -60,6 +57,7 @@ void LoadingPredictorTest::SetUp() { ...@@ -60,6 +57,7 @@ void LoadingPredictorTest::SetUp() {
auto mock = base::MakeUnique<StrictMock<MockResourcePrefetchPredictor>>( auto mock = base::MakeUnique<StrictMock<MockResourcePrefetchPredictor>>(
config, profile_.get()); config, profile_.get());
EXPECT_CALL(*mock, StartInitialization()); EXPECT_CALL(*mock, StartInitialization());
EXPECT_CALL(*mock, Shutdown());
EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl), _)) EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl), _))
.WillRepeatedly(Return(true)); .WillRepeatedly(Return(true));
EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl2), _)) EXPECT_CALL(*mock, GetPrefetchData(GURL(kUrl2), _))
...@@ -73,7 +71,7 @@ void LoadingPredictorTest::SetUp() { ...@@ -73,7 +71,7 @@ void LoadingPredictorTest::SetUp() {
} }
void LoadingPredictorTest::TearDown() { void LoadingPredictorTest::TearDown() {
predictor_ = nullptr; predictor_->Shutdown();
profile_->DestroyHistoryService(); profile_->DestroyHistoryService();
} }
......
...@@ -6,15 +6,39 @@ ...@@ -6,15 +6,39 @@
#include <utility> #include <utility>
#include "base/memory/ptr_util.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
#include "content/public/browser/resource_hints.h"
#include "net/base/net_errors.h"
namespace predictors { namespace predictors {
const int kAllowCredentialsOnPreconnectByDefault = true;
PreresolveInfo::PreresolveInfo(const GURL& in_url, size_t count)
: url(in_url),
queued_count(count),
inflight_count(0),
was_canceled(false) {}
PreresolveInfo::PreresolveInfo(const PreresolveInfo& other) = default;
PreresolveInfo::~PreresolveInfo() = default;
PreresolveJob::PreresolveJob(const GURL& in_url,
bool in_need_preconnect,
PreresolveInfo* in_info)
: url(in_url), need_preconnect(in_need_preconnect), info(in_info) {}
PreresolveJob::PreresolveJob(const PreresolveJob& other) = default;
PreresolveJob::~PreresolveJob() = default;
PreconnectManager::PreconnectManager( PreconnectManager::PreconnectManager(
base::WeakPtr<Delegate> delegate, base::WeakPtr<Delegate> delegate,
scoped_refptr<net::URLRequestContextGetter> context_getter) scoped_refptr<net::URLRequestContextGetter> context_getter)
: delegate_(std::move(delegate)), : delegate_(std::move(delegate)),
context_getter_(std::move(context_getter)) { context_getter_(std::move(context_getter)),
inflight_preresolves_count_(0),
weak_factory_(this) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
} }
...@@ -25,11 +49,106 @@ PreconnectManager::~PreconnectManager() { ...@@ -25,11 +49,106 @@ PreconnectManager::~PreconnectManager() {
void PreconnectManager::Start(const GURL& url, void PreconnectManager::Start(const GURL& url,
const std::vector<GURL>& preconnect_origins, const std::vector<GURL>& preconnect_origins,
const std::vector<GURL>& preresolve_hosts) { const std::vector<GURL>& preresolve_hosts) {
NOTIMPLEMENTED(); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (preresolve_info_.find(url) != preresolve_info_.end())
return;
auto iterator_and_whether_inserted = preresolve_info_.emplace(
url, base::MakeUnique<PreresolveInfo>(
url, preconnect_origins.size() + preresolve_hosts.size()));
PreresolveInfo* info = iterator_and_whether_inserted.first->second.get();
for (const GURL& origin : preconnect_origins)
queued_jobs_.emplace_back(origin, true, info);
for (const GURL& host : preresolve_hosts)
queued_jobs_.emplace_back(host, false, info);
TryToLaunchPreresolveJobs();
} }
void PreconnectManager::Stop(const GURL& url) { void PreconnectManager::Stop(const GURL& url) {
NOTIMPLEMENTED(); DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
auto it = preresolve_info_.find(url);
if (it == preresolve_info_.end()) {
return;
}
it->second->was_canceled = true;
}
void PreconnectManager::PreconnectUrl(
const GURL& url,
const GURL& first_party_for_cookies) const {
content::PreconnectUrl(context_getter_.get(), url, first_party_for_cookies, 1,
kAllowCredentialsOnPreconnectByDefault,
net::HttpRequestInfo::PRECONNECT_MOTIVATED);
}
int PreconnectManager::PreresolveUrl(
const GURL& url,
const net::CompletionCallback& callback) const {
return content::PreresolveUrl(context_getter_.get(), url, callback);
}
void PreconnectManager::TryToLaunchPreresolveJobs() {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
while (!queued_jobs_.empty() &&
inflight_preresolves_count_ < kMaxInflightPreresolves) {
auto& job = queued_jobs_.front();
PreresolveInfo* info = job.info;
if (!info->was_canceled) {
int status = PreresolveUrl(
job.url, base::Bind(&PreconnectManager::OnPreresolveFinished,
weak_factory_.GetWeakPtr(), job));
if (status == net::ERR_IO_PENDING) {
// Will complete asynchronously.
++info->inflight_count;
++inflight_preresolves_count_;
} else {
// Completed synchronously (was already cached by HostResolver), or else
// there was (equivalently) some network error that prevents us from
// finding the name. Status net::OK means it was "found."
FinishPreresolve(job, status == net::OK);
}
}
queued_jobs_.pop_front();
--info->queued_count;
if (info->is_done())
AllPreresolvesForUrlFinished(info);
}
}
void PreconnectManager::OnPreresolveFinished(const PreresolveJob& job,
int result) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
FinishPreresolve(job, result == net::OK);
--inflight_preresolves_count_;
--job.info->inflight_count;
if (job.info->is_done())
AllPreresolvesForUrlFinished(job.info);
TryToLaunchPreresolveJobs();
}
void PreconnectManager::FinishPreresolve(const PreresolveJob& job, bool found) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (found && job.need_preconnect && !job.info->was_canceled) {
PreconnectUrl(job.url, job.info->url);
}
}
void PreconnectManager::AllPreresolvesForUrlFinished(PreresolveInfo* info) {
DCHECK(info->is_done());
auto it = preresolve_info_.find(info->url);
DCHECK(it != preresolve_info_.end());
DCHECK(info == it->second.get());
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&Delegate::PreconnectFinished, delegate_, info->url));
preresolve_info_.erase(it);
} }
} // namespace predictors } // namespace predictors
...@@ -5,15 +5,49 @@ ...@@ -5,15 +5,49 @@
#ifndef CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_ #ifndef CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_
#define CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_ #define CHROME_BROWSER_PREDICTORS_PRECONNECT_MANAGER_H_
#include <list>
#include <map>
#include <memory>
#include <vector> #include <vector>
#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 "net/base/completion_callback.h"
#include "net/http/http_request_info.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace predictors { namespace predictors {
// Stores the status of all preconnects associated with a given |url|.
struct PreresolveInfo {
PreresolveInfo(const GURL& url, size_t count);
PreresolveInfo(const PreresolveInfo& other);
~PreresolveInfo();
bool is_done() const { return queued_count == 0 && inflight_count == 0; }
GURL url;
size_t queued_count;
size_t inflight_count = 0;
bool was_canceled = false;
};
// Stores all data need for running a preresolve and a subsequent optional
// preconnect for a |url|.
struct PreresolveJob {
PreresolveJob(const GURL& url, bool need_preconnect, PreresolveInfo* info);
PreresolveJob(const PreresolveJob& other);
~PreresolveJob();
GURL url;
bool need_preconnect;
// Raw pointer usage is fine here because even though PreresolveJob can
// outlive PreresolveInfo it's only accessed on PreconnectManager class
// context and PreresolveInfo lifetime is tied to PreconnectManager.
PreresolveInfo* info;
};
// PreconnectManager is responsible for preresolving and preconnecting to // PreconnectManager is responsible for preresolving and preconnecting to
// origins based on the input list of URLs. // origins based on the input list of URLs.
// - The input list of URLs is associated with a main frame url that can be // - The input list of URLs is associated with a main frame url that can be
...@@ -38,9 +72,11 @@ class PreconnectManager { ...@@ -38,9 +72,11 @@ class PreconnectManager {
virtual void PreconnectFinished(const GURL& url) = 0; virtual void PreconnectFinished(const GURL& url) = 0;
}; };
static const size_t kMaxInflightPreresolves = 3;
PreconnectManager(base::WeakPtr<Delegate> delegate, PreconnectManager(base::WeakPtr<Delegate> delegate,
scoped_refptr<net::URLRequestContextGetter> context_getter); scoped_refptr<net::URLRequestContextGetter> context_getter);
~PreconnectManager(); virtual ~PreconnectManager();
// Starts preconnect and preresolve jobs keyed by |url|. // Starts preconnect and preresolve jobs keyed by |url|.
void Start(const GURL& url, void Start(const GURL& url,
...@@ -49,9 +85,27 @@ class PreconnectManager { ...@@ -49,9 +85,27 @@ class PreconnectManager {
// No additional jobs keyed by the |url| will be queued after this. // No additional jobs keyed by the |url| will be queued after this.
void Stop(const GURL& url); void Stop(const GURL& url);
// Public for mocking in unit tests. Don't use, internal only.
virtual void PreconnectUrl(const GURL& url,
const GURL& first_party_for_cookies) const;
virtual int PreresolveUrl(const GURL& url,
const net::CompletionCallback& callback) const;
private: private:
void TryToLaunchPreresolveJobs();
void OnPreresolveFinished(const PreresolveJob& job, int result);
void FinishPreresolve(const PreresolveJob& job, bool found);
void AllPreresolvesForUrlFinished(PreresolveInfo* info);
base::WeakPtr<Delegate> delegate_; base::WeakPtr<Delegate> delegate_;
scoped_refptr<net::URLRequestContextGetter> context_getter_; scoped_refptr<net::URLRequestContextGetter> context_getter_;
std::list<PreresolveJob> queued_jobs_;
std::map<GURL, std::unique_ptr<PreresolveInfo>> preresolve_info_;
size_t inflight_preresolves_count_ = 0;
base::WeakPtrFactory<PreconnectManager> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PreconnectManager);
}; };
} // namespace predictors } // namespace predictors
......
// Copyright 2017 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/preconnect_manager.h"
#include "base/format_macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
#include "base/threading/thread_task_runner_handle.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/url_request/url_request_test_util.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::DoAll;
using testing::Mock;
using testing::Return;
using testing::SaveArg;
using testing::StrictMock;
namespace predictors {
class MockPreconnectManagerDelegate
: public PreconnectManager::Delegate,
public base::SupportsWeakPtr<MockPreconnectManagerDelegate> {
public:
MOCK_METHOD1(PreconnectFinished, void(const GURL&));
};
class MockPreconnectManager : public PreconnectManager {
public:
MockPreconnectManager(
base::WeakPtr<Delegate> delegate,
scoped_refptr<net::URLRequestContextGetter> context_getter);
MOCK_CONST_METHOD2(PreconnectUrl,
void(const GURL& url,
const GURL& first_party_for_cookies));
MOCK_CONST_METHOD2(PreresolveUrl,
int(const GURL& url,
const net::CompletionCallback& callback));
};
MockPreconnectManager::MockPreconnectManager(
base::WeakPtr<Delegate> delegate,
scoped_refptr<net::URLRequestContextGetter> context_getter)
: PreconnectManager(delegate, context_getter) {}
class PreconnectManagerTest : public testing::Test {
public:
PreconnectManagerTest();
~PreconnectManagerTest() override;
protected:
content::TestBrowserThreadBundle thread_bundle_;
std::unique_ptr<StrictMock<MockPreconnectManagerDelegate>> mock_delegate_;
scoped_refptr<net::URLRequestContextGetter> context_getter_;
std::unique_ptr<StrictMock<MockPreconnectManager>> preconnect_manager_;
private:
DISALLOW_COPY_AND_ASSIGN(PreconnectManagerTest);
};
PreconnectManagerTest::PreconnectManagerTest()
: mock_delegate_(
base::MakeUnique<StrictMock<MockPreconnectManagerDelegate>>()),
context_getter_(new net::TestURLRequestContextGetter(
base::ThreadTaskRunnerHandle::Get())),
preconnect_manager_(base::MakeUnique<StrictMock<MockPreconnectManager>>(
mock_delegate_->AsWeakPtr(),
context_getter_)) {}
PreconnectManagerTest::~PreconnectManagerTest() = default;
TEST_F(PreconnectManagerTest, TestStartOneUrlPreresolve) {
GURL main_frame_url("http://google.com");
GURL url_to_preresolve("http://cdn.google.com");
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preresolve, _))
.WillOnce(Return(net::OK));
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url));
preconnect_manager_->Start(main_frame_url, std::vector<GURL>(),
{url_to_preresolve});
// Wait for PreconnectFinished task posted to the UI thread.
base::RunLoop().RunUntilIdle();
}
TEST_F(PreconnectManagerTest, TestStartOneUrlPreconnect) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
.WillOnce(Return(net::OK));
EXPECT_CALL(*preconnect_manager_,
PreconnectUrl(url_to_preconnect, main_frame_url));
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url));
preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
std::vector<GURL>());
base::RunLoop().RunUntilIdle();
}
TEST_F(PreconnectManagerTest, TestStopOneUrlBeforePreconnect) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
net::CompletionCallback callback;
// Preconnect job isn't started before preresolve is completed asynchronously.
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
.WillOnce(DoAll(SaveArg<1>(&callback), Return(net::ERR_IO_PENDING)));
preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
std::vector<GURL>());
// Stop all jobs for |main_frame_url| before we get the callback.
preconnect_manager_->Stop(main_frame_url);
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url));
callback.Run(net::OK);
base::RunLoop().RunUntilIdle();
}
TEST_F(PreconnectManagerTest, TestGetCallbackAfterDestruction) {
GURL main_frame_url("http://google.com");
GURL url_to_preconnect("http://cdn.google.com");
net::CompletionCallback callback;
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect, _))
.WillOnce(DoAll(SaveArg<1>(&callback), Return(net::ERR_IO_PENDING)));
preconnect_manager_->Start(main_frame_url, {url_to_preconnect},
std::vector<GURL>());
// Callback may outlive PreconnectManager but it shouldn't cause a crash.
preconnect_manager_ = nullptr;
callback.Run(net::OK);
base::RunLoop().RunUntilIdle();
}
TEST_F(PreconnectManagerTest, TestUnqueuedPreresolvesCanceled) {
GURL main_frame_url("http://google.com");
size_t count = PreconnectManager::kMaxInflightPreresolves;
std::vector<GURL> urls_to_preconnect;
// Allocate the space for callbacks at once because we need stable pointers.
std::vector<net::CompletionCallback> callbacks(count);
for (size_t i = 0; i < count; ++i) {
// Exactly PreconnectManager::kMaxInflightPreresolves should be preresolved.
urls_to_preconnect.emplace_back(
base::StringPrintf("http://cdn%" PRIuS ".google.com", i));
EXPECT_CALL(*preconnect_manager_,
PreresolveUrl(urls_to_preconnect.back(), _))
.WillOnce(
DoAll(SaveArg<1>(&callbacks[i]), Return(net::ERR_IO_PENDING)));
}
// This url shouldn't be preresolved.
urls_to_preconnect.emplace_back("http://no.preresolve.com");
preconnect_manager_->Start(main_frame_url, urls_to_preconnect,
std::vector<GURL>());
preconnect_manager_->Stop(main_frame_url);
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url));
for (auto& callback : callbacks)
callback.Run(net::OK);
base::RunLoop().RunUntilIdle();
}
TEST_F(PreconnectManagerTest, TestTwoConcurrentMainFrameUrls) {
GURL main_frame_url1("http://google.com");
GURL url_to_preconnect1("http://cdn.google.com");
net::CompletionCallback callback1;
GURL main_frame_url2("http://facebook.com");
GURL url_to_preconnect2("http://cdn.facebook.com");
net::CompletionCallback callback2;
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect1, _))
.WillOnce(DoAll(SaveArg<1>(&callback1), Return(net::ERR_IO_PENDING)));
EXPECT_CALL(*preconnect_manager_, PreresolveUrl(url_to_preconnect2, _))
.WillOnce(DoAll(SaveArg<1>(&callback2), Return(net::ERR_IO_PENDING)));
preconnect_manager_->Start(main_frame_url1, {url_to_preconnect1},
std::vector<GURL>());
preconnect_manager_->Start(main_frame_url2, {url_to_preconnect2},
std::vector<GURL>());
// Check that the first url didn't block the second one.
Mock::VerifyAndClearExpectations(preconnect_manager_.get());
preconnect_manager_->Stop(main_frame_url2);
// Stopping the second url shouldn't stop the first one.
EXPECT_CALL(*preconnect_manager_,
PreconnectUrl(url_to_preconnect1, main_frame_url1));
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url1));
callback1.Run(net::OK);
// No preconnect for the second url.
EXPECT_CALL(*mock_delegate_, PreconnectFinished(main_frame_url2));
callback2.Run(net::OK);
base::RunLoop().RunUntilIdle();
}
} // namespace predictors
...@@ -145,6 +145,9 @@ class ResourcePrefetchPredictorTest : public testing::Test { ...@@ -145,6 +145,9 @@ class ResourcePrefetchPredictorTest : public testing::Test {
} }
void ResetPredictor(bool small_db = true) { void ResetPredictor(bool small_db = true) {
if (loading_predictor_)
loading_predictor_->Shutdown();
LoadingPredictorConfig config; LoadingPredictorConfig config;
PopulateTestConfig(&config, small_db); PopulateTestConfig(&config, small_db);
loading_predictor_ = loading_predictor_ =
...@@ -175,13 +178,10 @@ class ResourcePrefetchPredictorTest : public testing::Test { ...@@ -175,13 +178,10 @@ class ResourcePrefetchPredictorTest : public testing::Test {
}; };
ResourcePrefetchPredictorTest::ResourcePrefetchPredictorTest() ResourcePrefetchPredictorTest::ResourcePrefetchPredictorTest()
: profile_(new TestingProfile()), : profile_(base::MakeUnique<TestingProfile>()),
mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()) {} mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()) {}
ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() { ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() = default;
profile_.reset(NULL);
base::RunLoop().RunUntilIdle();
}
void ResourcePrefetchPredictorTest::SetUp() { void ResourcePrefetchPredictorTest::SetUp() {
InitializeSampleData(); InitializeSampleData();
...@@ -215,8 +215,7 @@ void ResourcePrefetchPredictorTest::TearDown() { ...@@ -215,8 +215,7 @@ void ResourcePrefetchPredictorTest::TearDown() {
mock_tables_->host_redirect_table_.data_); mock_tables_->host_redirect_table_.data_);
EXPECT_EQ(*predictor_->origin_data_->data_cache_, EXPECT_EQ(*predictor_->origin_data_->data_cache_,
mock_tables_->origin_table_.data_); mock_tables_->origin_table_.data_);
loading_predictor_ = nullptr; loading_predictor_->Shutdown();
predictor_ = nullptr;
profile_->DestroyHistoryService(); profile_->DestroyHistoryService();
} }
......
...@@ -3252,6 +3252,7 @@ test("unit_tests") { ...@@ -3252,6 +3252,7 @@ test("unit_tests") {
"../browser/predictors/loading_stats_collector_unittest.cc", "../browser/predictors/loading_stats_collector_unittest.cc",
"../browser/predictors/loading_test_util.cc", "../browser/predictors/loading_test_util.cc",
"../browser/predictors/loading_test_util.h", "../browser/predictors/loading_test_util.h",
"../browser/predictors/preconnect_manager_unittest.cc",
"../browser/predictors/resource_prefetch_common_unittest.cc", "../browser/predictors/resource_prefetch_common_unittest.cc",
"../browser/predictors/resource_prefetch_predictor_tables_unittest.cc", "../browser/predictors/resource_prefetch_predictor_tables_unittest.cc",
"../browser/predictors/resource_prefetch_predictor_unittest.cc", "../browser/predictors/resource_prefetch_predictor_unittest.cc",
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "content/browser/loader/resource_dispatcher_host_impl.h" #include "content/browser/loader/resource_dispatcher_host_impl.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/resource_hints.h" #include "content/public/browser/resource_hints.h"
#include "net/base/address_list.h" #include "net/base/address_list.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
...@@ -19,6 +18,7 @@ ...@@ -19,6 +18,7 @@
#include "net/log/net_log_with_source.h" #include "net/log/net_log_with_source.h"
#include "net/url_request/http_user_agent_settings.h" #include "net/url_request/http_user_agent_settings.h"
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
namespace content { namespace content {
...@@ -45,7 +45,7 @@ void OnResolveComplete(std::unique_ptr<RequestHolder> request_holder, ...@@ -45,7 +45,7 @@ void OnResolveComplete(std::unique_ptr<RequestHolder> request_holder,
} // namespace } // namespace
void PreconnectUrl(content::ResourceContext* resource_context, void PreconnectUrl(net::URLRequestContextGetter* getter,
const GURL& url, const GURL& url,
const GURL& first_party_for_cookies, const GURL& first_party_for_cookies,
int count, int count,
...@@ -54,15 +54,19 @@ void PreconnectUrl(content::ResourceContext* resource_context, ...@@ -54,15 +54,19 @@ void PreconnectUrl(content::ResourceContext* resource_context,
DCHECK(ResourceDispatcherHostImpl::Get() DCHECK(ResourceDispatcherHostImpl::Get()
->io_thread_task_runner() ->io_thread_task_runner()
->BelongsToCurrentThread()); ->BelongsToCurrentThread());
DCHECK(resource_context); DCHECK(getter);
net::URLRequestContext* context = resource_context->GetRequestContext(); net::URLRequestContext* request_context = getter->GetURLRequestContext();
net::HttpTransactionFactory* factory = context->http_transaction_factory(); if (!request_context)
return;
net::HttpTransactionFactory* factory =
request_context->http_transaction_factory();
net::HttpNetworkSession* session = factory->GetSession(); net::HttpNetworkSession* session = factory->GetSession();
std::string user_agent; std::string user_agent;
if (context->http_user_agent_settings()) if (request_context->http_user_agent_settings())
user_agent = context->http_user_agent_settings()->GetUserAgent(); user_agent = request_context->http_user_agent_settings()->GetUserAgent();
net::HttpRequestInfo request_info; net::HttpRequestInfo request_info;
request_info.url = url; request_info.url = url;
request_info.method = "GET"; request_info.method = "GET";
...@@ -70,7 +74,7 @@ void PreconnectUrl(content::ResourceContext* resource_context, ...@@ -70,7 +74,7 @@ void PreconnectUrl(content::ResourceContext* resource_context,
user_agent); user_agent);
request_info.motivation = motivation; request_info.motivation = motivation;
net::NetworkDelegate* delegate = context->network_delegate(); net::NetworkDelegate* delegate = request_context->network_delegate();
if (delegate->CanEnablePrivacyMode(url, first_party_for_cookies)) if (delegate->CanEnablePrivacyMode(url, first_party_for_cookies))
request_info.privacy_mode = net::PRIVACY_MODE_ENABLED; request_info.privacy_mode = net::PRIVACY_MODE_ENABLED;
...@@ -88,13 +92,17 @@ void PreconnectUrl(content::ResourceContext* resource_context, ...@@ -88,13 +92,17 @@ void PreconnectUrl(content::ResourceContext* resource_context,
http_stream_factory->PreconnectStreams(count, request_info); http_stream_factory->PreconnectStreams(count, request_info);
} }
int PreresolveUrl(content::ResourceContext* resource_context, int PreresolveUrl(net::URLRequestContextGetter* getter,
const GURL& url, const GURL& url,
const net::CompletionCallback& callback) { const net::CompletionCallback& callback) {
DCHECK(ResourceDispatcherHostImpl::Get() DCHECK(ResourceDispatcherHostImpl::Get()
->io_thread_task_runner() ->io_thread_task_runner()
->BelongsToCurrentThread()); ->BelongsToCurrentThread());
DCHECK(resource_context); DCHECK(getter);
net::URLRequestContext* request_context = getter->GetURLRequestContext();
if (!request_context)
return net::ERR_CONTEXT_SHUT_DOWN;
auto request_holder = base::MakeUnique<RequestHolder>(); auto request_holder = base::MakeUnique<RequestHolder>();
auto addresses = base::MakeUnique<net::AddressList>(); auto addresses = base::MakeUnique<net::AddressList>();
...@@ -104,7 +112,7 @@ int PreresolveUrl(content::ResourceContext* resource_context, ...@@ -104,7 +112,7 @@ int PreresolveUrl(content::ResourceContext* resource_context,
std::unique_ptr<net::HostResolver::Request>* out_request = std::unique_ptr<net::HostResolver::Request>* out_request =
request_holder->GetRequest(); request_holder->GetRequest();
net::HostResolver* resolver = resource_context->GetHostResolver(); net::HostResolver* resolver = request_context->host_resolver();
net::HostResolver::RequestInfo resolve_info(net::HostPortPair::FromURL(url)); net::HostResolver::RequestInfo resolve_info(net::HostPortPair::FromURL(url));
resolve_info.set_is_speculative(true); resolve_info.set_is_speculative(true);
return resolver->Resolve( return resolver->Resolve(
......
...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
class GURL; class GURL;
namespace content { namespace net {
class ResourceContext; class URLRequestContextGetter;
} }
namespace content { namespace content {
...@@ -28,7 +28,7 @@ namespace content { ...@@ -28,7 +28,7 @@ namespace content {
// Note: This should only be called on the IO thread, with a valid // Note: This should only be called on the IO thread, with a valid
// URLRequestContextGetter. // URLRequestContextGetter.
CONTENT_EXPORT void PreconnectUrl( CONTENT_EXPORT void PreconnectUrl(
content::ResourceContext* resource_context, net::URLRequestContextGetter* getter,
const GURL& url, const GURL& url,
const GURL& first_party_for_cookies, const GURL& first_party_for_cookies,
int count, int count,
...@@ -37,7 +37,7 @@ CONTENT_EXPORT void PreconnectUrl( ...@@ -37,7 +37,7 @@ CONTENT_EXPORT void PreconnectUrl(
// Issues a DNS request to |url|. Note that these requests are sent to the host // Issues a DNS request to |url|. Note that these requests are sent to the host
// resolver with priority net::IDLE. // resolver with priority net::IDLE.
CONTENT_EXPORT int PreresolveUrl(content::ResourceContext* resource_context, CONTENT_EXPORT int PreresolveUrl(net::URLRequestContextGetter* getter,
const GURL& url, const GURL& url,
const net::CompletionCallback& callback); const net::CompletionCallback& callback);
......
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