Commit fc622277 authored by Dan Harrington's avatar Dan Harrington Committed by Commit Bot

Cancel auto-fetch requests upon successful navigation

Intercept DidFinishNavigation events and cancel in-flight auto-fetch requests.

Bug: 883486
Change-Id: I41d5f1fdcc22c119fa0024abc1dd8fea13483576
Reviewed-on: https://chromium-review.googlesource.com/c/1313249
Commit-Queue: Dan H <harringtond@google.com>
Reviewed-by: default avatarJochen Eisinger <jochen@chromium.org>
Reviewed-by: default avatarCarlos Knippschild <carlosk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608158}
parent b8bda029
...@@ -4096,6 +4096,8 @@ jumbo_split_static_library("browser") { ...@@ -4096,6 +4096,8 @@ jumbo_split_static_library("browser") {
if (enable_offline_pages) { if (enable_offline_pages) {
sources += [ sources += [
"offline_pages/auto_fetch_page_load_watcher.cc",
"offline_pages/auto_fetch_page_load_watcher.h",
"offline_pages/background_loader_offliner.cc", "offline_pages/background_loader_offliner.cc",
"offline_pages/background_loader_offliner.h", "offline_pages/background_loader_offliner.h",
"offline_pages/download_archive_manager.cc", "offline_pages/download_archive_manager.cc",
......
// 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/offline_pages/auto_fetch_page_load_watcher.h"
#include <memory>
#include "base/macros.h"
#include "chrome/browser/offline_pages/offline_page_auto_fetcher.h"
#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service.h"
#include "chrome/browser/offline_pages/offline_page_auto_fetcher_service_factory.h"
#include "chrome/browser/offline_pages/request_coordinator_factory.h"
#include "components/offline_pages/core/background/request_coordinator.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace offline_pages {
// Observes a WebContents to relay navigation events to
// AutoFetchPageLoadWatcher.
class AutoFetchPageLoadWatcher::NavigationObserver
: public content::WebContentsObserver,
public content::WebContentsUserData<
AutoFetchPageLoadWatcher::NavigationObserver> {
public:
explicit NavigationObserver(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
helper_ = OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
web_contents->GetBrowserContext())
->page_load_watcher();
DCHECK(helper_);
}
// content::WebContentsObserver implementation.
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override {
if (!navigation_handle->IsInMainFrame() ||
!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage())
return;
// Note: The redirect chain includes the final URL. We consider all URLs
// along the redirect chain as successful.
for (const auto& u : navigation_handle->GetRedirectChain()) {
helper_->HandlePageNavigation(u);
}
}
private:
AutoFetchPageLoadWatcher* helper_;
DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
};
// static
void AutoFetchPageLoadWatcher::CreateForWebContents(
content::WebContents* web_contents) {
OfflinePageAutoFetcherService* service =
OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
web_contents->GetBrowserContext());
// Don't try to create if the service isn't available (happens in incognito
// mode).
if (service) {
NavigationObserver::CreateForWebContents(web_contents);
}
}
AutoFetchPageLoadWatcher::AutoFetchPageLoadWatcher(
RequestCoordinator* request_coordinator)
: request_coordinator_(request_coordinator) {
request_coordinator_->AddObserver(this);
request_coordinator_->GetAllRequests(
base::BindOnce(&AutoFetchPageLoadWatcher::ObserverInitialize,
weak_ptr_factory_.GetWeakPtr()));
}
AutoFetchPageLoadWatcher::~AutoFetchPageLoadWatcher() {
request_coordinator_->RemoveObserver(this);
}
void AutoFetchPageLoadWatcher::OnAdded(const SavePageRequest& request) {
if (!observer_ready_)
return;
if (request.client_id().name_space == kAutoAsyncNamespace) {
live_auto_fetch_requests_[request.url()].push_back(request.request_id());
}
}
void AutoFetchPageLoadWatcher::OnCompleted(
const SavePageRequest& request,
RequestNotifier::BackgroundSavePageResult status) {
if (!observer_ready_)
return;
// A SavePageRequest is complete, remove our bookeeping of it in
// |live_auto_fetch_requests_|.
auto iter = live_auto_fetch_requests_.find(request.url());
if (iter != live_auto_fetch_requests_.end()) {
std::vector<int64_t>& id_list = iter->second;
auto id_iter =
std::find(id_list.begin(), id_list.end(), request.request_id());
if (id_iter != id_list.end()) {
id_list.erase(id_iter);
if (id_list.empty())
live_auto_fetch_requests_.erase(iter);
}
}
}
void AutoFetchPageLoadWatcher::RemoveRequests(
const std::vector<int64_t>& request_ids) {
request_coordinator_->RemoveRequests(request_ids, base::DoNothing());
}
void AutoFetchPageLoadWatcher::HandlePageNavigation(const GURL& url) {
// Early exit for the common-case.
if (observer_ready_ && live_auto_fetch_requests_.empty()) {
return;
}
// Note: It is possible that this method is called before
// ObserverInitialized, in which case we have to defer handling of the
// event. Never accumulate more than a few, so we can't have a boundless
// array if ObserverInitialize is never called.
if (!observer_ready_) {
if (pages_loaded_before_observer_ready_.size() < 10)
pages_loaded_before_observer_ready_.push_back(url);
return;
}
auto iter = live_auto_fetch_requests_.find(url);
if (iter == live_auto_fetch_requests_.end())
return;
RemoveRequests(iter->second);
}
void AutoFetchPageLoadWatcher::ObserverInitialize(
std::vector<std::unique_ptr<SavePageRequest>> all_requests) {
observer_ready_ = true;
for (const std::unique_ptr<SavePageRequest>& request : all_requests) {
OnAdded(*request);
}
for (const GURL& url : pages_loaded_before_observer_ready_) {
HandlePageNavigation(url);
}
pages_loaded_before_observer_ready_.clear();
}
} // namespace offline_pages
// 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_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
#define CHROME_BROWSER_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/background/request_coordinator.h"
#include "components/offline_pages/core/client_id.h"
#include "url/gurl.h"
namespace content {
class WebContents;
} // namespace content
namespace offline_pages {
class SavePageRequest;
class RequestCoordinator;
// Cancels active auto fetch requests if a page loads.
class AutoFetchPageLoadWatcher : public RequestCoordinator::Observer {
public:
static void CreateForWebContents(content::WebContents* web_contents);
explicit AutoFetchPageLoadWatcher(RequestCoordinator* request_coordinator);
~AutoFetchPageLoadWatcher() override;
// RequestCoordinator::Observer methods. These keep
// |live_auto_fetch_requests_| in sync with the state of RequestCoordinator.
void OnAdded(const SavePageRequest& request) override;
void OnCompleted(const SavePageRequest& request,
RequestNotifier::BackgroundSavePageResult status) override;
void OnChanged(const SavePageRequest& request) override {}
void OnNetworkProgress(const SavePageRequest& request,
int64_t received_bytes) override {}
protected:
class NavigationObserver;
// Virtual for testing only.
virtual void RemoveRequests(const std::vector<int64_t>& request_ids);
// Called when navigation completes. Triggers cancellation of any
// in-flight auto fetch requests that match a successful navigation.
void HandlePageNavigation(const GURL& url);
void ObserverInitialize(
std::vector<std::unique_ptr<SavePageRequest>> all_requests);
offline_pages::RequestCoordinator* GetRequestCoordinator();
// Whether ObserverInitialize has been called.
bool observer_ready_ = false;
RequestCoordinator* request_coordinator_;
std::vector<GURL> pages_loaded_before_observer_ready_;
// This represents the set of auto fetch request IDs currently in the
// RequestCoordinator's queue, mapped by URL.
std::map<GURL, std::vector<int64_t>> live_auto_fetch_requests_;
base::WeakPtrFactory<AutoFetchPageLoadWatcher> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AutoFetchPageLoadWatcher);
};
} // namespace offline_pages
#endif // CHROME_BROWSER_OFFLINE_PAGES_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
// 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/offline_pages/auto_fetch_page_load_watcher.h"
#include <memory>
#include <string>
#include <utility>
#include "base/test/bind_test_util.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/offline_pages/request_coordinator_factory.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "chrome/test/base/testing_profile.h"
#include "components/offline_pages/core/background/request_coordinator_stub_taco.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "content/public/test/navigation_simulator.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace offline_pages {
namespace {
using content::NavigationSimulator;
GURL TestURL() {
return GURL("http://www.url.com");
}
SavePageRequest TestRequest(int64_t id, const GURL& url = TestURL()) {
return SavePageRequest(id, url,
ClientId(kAutoAsyncNamespace, std::to_string(id)),
base::Time::Now(), false);
}
// For access to protected methods.
class TestAutoFetchPageLoadWatcher : public AutoFetchPageLoadWatcher {
public:
explicit TestAutoFetchPageLoadWatcher(RequestCoordinator* request_coordinator)
: AutoFetchPageLoadWatcher(request_coordinator) {}
void RemoveRequests(const std::vector<int64_t>& request_ids) override {
removed_ids_ = request_ids;
}
std::vector<int64_t> removed_ids() const { return removed_ids_; }
std::map<GURL, std::vector<int64_t>>* live_auto_fetch_requests() {
return &live_auto_fetch_requests_;
}
using AutoFetchPageLoadWatcher::HandlePageNavigation;
using AutoFetchPageLoadWatcher::ObserverInitialize;
private:
std::vector<int64_t> removed_ids_;
};
// Tests AutoFetchPageLoadWatcher in a realistic way by simulating navigations.
class AutoFetchPageLoadWatcherNavigationTest
: public ChromeRenderViewHostTestHarness {
public:
AutoFetchPageLoadWatcherNavigationTest() = default;
~AutoFetchPageLoadWatcherNavigationTest() override = default;
void SetUp() override {
ChromeRenderViewHostTestHarness::SetUp();
RequestCoordinatorFactory::GetInstance()->SetTestingFactoryAndUse(
profile(), request_coordinator_taco_.FactoryFunction());
AutoFetchPageLoadWatcher::CreateForWebContents(web_contents());
}
std::unique_ptr<NavigationSimulator> CreateNavigation(const GURL& url) {
return NavigationSimulator::CreateRendererInitiated(url, main_rfh());
}
RequestCoordinator* request_coordinator() {
return request_coordinator_taco_.request_coordinator();
}
void AddAutoSavePageRequest() {
RequestCoordinator::SavePageLaterParams params;
params.url = TestURL();
params.client_id = ClientId(kAutoAsyncNamespace, "request1");
request_coordinator()->SavePageLater(params, base::DoNothing());
}
std::vector<GURL> RequestsInQueue() {
std::vector<GURL> request_urls;
request_coordinator()->GetAllRequests(base::BindLambdaForTesting(
[&](std::vector<std::unique_ptr<SavePageRequest>> requests) {
for (const auto& request : requests) {
request_urls.push_back(request->url());
}
}));
RunUntilIdle();
return request_urls;
}
void RunUntilIdle() { thread_bundle()->RunUntilIdle(); }
private:
RequestCoordinatorStubTaco request_coordinator_taco_;
DISALLOW_COPY_AND_ASSIGN(AutoFetchPageLoadWatcherNavigationTest);
};
// Navigation results in an error page, and has no effect on
// AutoFetchPageLoadWatcher.
TEST_F(AutoFetchPageLoadWatcherNavigationTest, NavigateToErrorPage) {
AddAutoSavePageRequest();
RunUntilIdle();
std::unique_ptr<NavigationSimulator> simulator = CreateNavigation(TestURL());
simulator->Start();
simulator->Fail(net::ERR_TIMED_OUT);
simulator->CommitErrorPage();
std::vector<GURL> expected_requests{TestURL()};
EXPECT_EQ(expected_requests, RequestsInQueue());
}
// Successful navigation results in cancellation of request.
TEST_F(AutoFetchPageLoadWatcherNavigationTest, NavigateAndCancel) {
AddAutoSavePageRequest();
RunUntilIdle();
std::unique_ptr<NavigationSimulator> simulator = CreateNavigation(TestURL());
simulator->Start();
simulator->Commit();
std::vector<GURL> expected_requests{};
EXPECT_EQ(expected_requests, RequestsInQueue());
}
TEST_F(AutoFetchPageLoadWatcherNavigationTest, NavigateToDifferentURL) {
AddAutoSavePageRequest();
RunUntilIdle();
std::unique_ptr<NavigationSimulator> simulator =
CreateNavigation(GURL("http://www.different.com"));
simulator->Start();
simulator->Commit();
std::vector<GURL> expected_requests{TestURL()};
EXPECT_EQ(expected_requests, RequestsInQueue());
}
TEST_F(AutoFetchPageLoadWatcherNavigationTest, RedirectToAndCancel) {
AddAutoSavePageRequest();
RunUntilIdle();
std::unique_ptr<NavigationSimulator> simulator =
CreateNavigation(GURL("http://different.com"));
simulator->Start();
simulator->Redirect(TestURL());
simulator->Commit();
std::vector<GURL> expected_requests{};
EXPECT_EQ(expected_requests, RequestsInQueue());
}
TEST_F(AutoFetchPageLoadWatcherNavigationTest, RedirectFromAndCancel) {
AddAutoSavePageRequest();
RunUntilIdle();
std::unique_ptr<NavigationSimulator> simulator = CreateNavigation(TestURL());
simulator->Start();
simulator->Redirect(GURL("http://different.com"));
simulator->Commit();
std::vector<GURL> expected_requests{};
EXPECT_EQ(expected_requests, RequestsInQueue());
}
// Tests some details of AutoFetchPageLoadWatcher
class AutoFetchPageLoadWatcherTest : public testing::Test {
public:
AutoFetchPageLoadWatcherTest() {}
~AutoFetchPageLoadWatcherTest() override {}
void SetUp() override {
testing::Test::SetUp();
taco_.CreateRequestCoordinator();
}
RequestCoordinator* request_coordinator() {
return taco_.request_coordinator();
}
private:
scoped_refptr<base::TestSimpleTaskRunner> task_runner_ =
base::MakeRefCounted<base::TestSimpleTaskRunner>();
base::ThreadTaskRunnerHandle handle_{task_runner_};
RequestCoordinatorStubTaco taco_;
};
// Simulate navigation to a URL prior to ObserverInitialize. Verify the
// RemoveRequests is called.
TEST_F(AutoFetchPageLoadWatcherTest, NavigateBeforeObserverInitialize) {
TestAutoFetchPageLoadWatcher tab_helper(request_coordinator());
tab_helper.HandlePageNavigation(TestURL());
std::vector<std::unique_ptr<SavePageRequest>> all_requests;
all_requests.push_back(std::make_unique<SavePageRequest>(TestRequest(1)));
all_requests.push_back(std::make_unique<SavePageRequest>(
TestRequest(2, GURL("http://different.com"))));
tab_helper.ObserverInitialize(std::move(all_requests));
std::vector<int64_t> expected_requests{1};
EXPECT_EQ(expected_requests, tab_helper.removed_ids());
}
TEST_F(AutoFetchPageLoadWatcherTest, OnCompletedNoRequest) {
TestAutoFetchPageLoadWatcher tab_helper(request_coordinator());
tab_helper.ObserverInitialize({});
tab_helper.OnCompleted(TestRequest(1),
RequestNotifier::BackgroundSavePageResult());
// Nothing happens, just verify there is no crash.
SUCCEED();
}
TEST_F(AutoFetchPageLoadWatcherTest, OnCompletedOneRequestWithURL) {
TestAutoFetchPageLoadWatcher tab_helper(request_coordinator());
tab_helper.ObserverInitialize({});
std::map<GURL, std::vector<int64_t>>* requests =
tab_helper.live_auto_fetch_requests();
tab_helper.OnAdded(TestRequest(1));
ASSERT_EQ(1ul, requests->count(TestURL()));
tab_helper.OnCompleted(TestRequest(1),
RequestNotifier::BackgroundSavePageResult());
EXPECT_EQ(0ul, requests->count(TestURL()));
}
// Verify multiple requests with the same URL are handled as expected.
TEST_F(AutoFetchPageLoadWatcherTest, OnCompletedMultipleRequestsWithURL) {
TestAutoFetchPageLoadWatcher tab_helper(request_coordinator());
tab_helper.ObserverInitialize({});
// Three requests with the same URL.
tab_helper.OnAdded(TestRequest(1));
tab_helper.OnAdded(TestRequest(2));
tab_helper.OnAdded(TestRequest(3));
// Only one is completed.
tab_helper.OnCompleted(TestRequest(2),
RequestNotifier::BackgroundSavePageResult());
std::vector<int64_t> expected_requests = {1, 3};
EXPECT_EQ(expected_requests,
(*tab_helper.live_auto_fetch_requests())[TestURL()]);
}
} // namespace
} // namespace offline_pages
...@@ -71,7 +71,8 @@ class OfflinePageAutoFetcherService::TaskToken { ...@@ -71,7 +71,8 @@ class OfflinePageAutoFetcherService::TaskToken {
OfflinePageAutoFetcherService::OfflinePageAutoFetcherService( OfflinePageAutoFetcherService::OfflinePageAutoFetcherService(
RequestCoordinator* request_coordinator) RequestCoordinator* request_coordinator)
: request_coordinator_(request_coordinator) {} : page_load_watcher_(request_coordinator),
request_coordinator_(request_coordinator) {}
OfflinePageAutoFetcherService::~OfflinePageAutoFetcherService() {} OfflinePageAutoFetcherService::~OfflinePageAutoFetcherService() {}
void OfflinePageAutoFetcherService::TrySchedule(bool user_requested, void OfflinePageAutoFetcherService::TrySchedule(bool user_requested,
......
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
#define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_ #define CHROME_BROWSER_OFFLINE_PAGES_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
#include <memory> #include <memory>
#include <utility>
#include <vector> #include <vector>
#include "base/callback_forward.h" #include "base/callback_forward.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
#include "chrome/common/offline_page_auto_fetcher.mojom.h" #include "chrome/common/offline_page_auto_fetcher.mojom.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/offline_pages/core/background/request_queue_results.h" #include "components/offline_pages/core/background/request_queue_results.h"
...@@ -55,6 +57,8 @@ class OfflinePageAutoFetcherService : public KeyedService { ...@@ -55,6 +57,8 @@ class OfflinePageAutoFetcherService : public KeyedService {
RequestCoordinator* request_coordinator); RequestCoordinator* request_coordinator);
~OfflinePageAutoFetcherService() override; ~OfflinePageAutoFetcherService() override;
AutoFetchPageLoadWatcher* page_load_watcher() { return &page_load_watcher_; }
// Auto fetching interface. Schedules and cancels fetch requests. // Auto fetching interface. Schedules and cancels fetch requests.
void TrySchedule(bool user_requested, void TrySchedule(bool user_requested,
...@@ -114,6 +118,7 @@ class OfflinePageAutoFetcherService : public KeyedService { ...@@ -114,6 +118,7 @@ class OfflinePageAutoFetcherService : public KeyedService {
std::vector<std::unique_ptr<SavePageRequest>> requests); std::vector<std::unique_ptr<SavePageRequest>> requests);
void CancelScheduleStep3(TaskToken token, const MultipleItemStatuses&); void CancelScheduleStep3(TaskToken token, const MultipleItemStatuses&);
AutoFetchPageLoadWatcher page_load_watcher_;
RequestCoordinator* request_coordinator_; RequestCoordinator* request_coordinator_;
// TODO(harringtond): Pull out task management into another class, or use // TODO(harringtond): Pull out task management into another class, or use
// offline_pages::TaskQueue. // offline_pages::TaskQueue.
......
...@@ -21,8 +21,11 @@ OfflinePageAutoFetcherServiceFactory::GetInstance() { ...@@ -21,8 +21,11 @@ OfflinePageAutoFetcherServiceFactory::GetInstance() {
OfflinePageAutoFetcherService* OfflinePageAutoFetcherService*
OfflinePageAutoFetcherServiceFactory::GetForBrowserContext( OfflinePageAutoFetcherServiceFactory::GetForBrowserContext(
content::BrowserContext* context) { content::BrowserContext* context) {
return static_cast<OfflinePageAutoFetcherService*>( KeyedService* service =
GetInstance()->GetServiceForBrowserContext(context, true)); GetInstance()->GetServiceForBrowserContext(context, true);
if (!service)
return nullptr;
return static_cast<OfflinePageAutoFetcherService*>(service);
} }
OfflinePageAutoFetcherServiceFactory::OfflinePageAutoFetcherServiceFactory() OfflinePageAutoFetcherServiceFactory::OfflinePageAutoFetcherServiceFactory()
......
...@@ -204,7 +204,7 @@ class OfflinePageTabHelper ...@@ -204,7 +204,7 @@ class OfflinePageTabHelper
bool reloading_url_on_net_error_ = false; bool reloading_url_on_net_error_ = false;
// Service, overlives this object. // Service, outlives this object.
PrefetchService* prefetch_service_ = nullptr; PrefetchService* prefetch_service_ = nullptr;
// Table of OfflinePages policies. // Table of OfflinePages policies.
......
...@@ -122,6 +122,7 @@ ...@@ -122,6 +122,7 @@
#endif #endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES) #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
#include "chrome/browser/offline_pages/auto_fetch_page_load_watcher.h"
#include "chrome/browser/offline_pages/offline_page_tab_helper.h" #include "chrome/browser/offline_pages/offline_page_tab_helper.h"
#include "chrome/browser/offline_pages/recent_tab_helper.h" #include "chrome/browser/offline_pages/recent_tab_helper.h"
#endif #endif
...@@ -323,6 +324,7 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) { ...@@ -323,6 +324,7 @@ void TabHelpers::AttachTabHelpers(WebContents* web_contents) {
#if BUILDFLAG(ENABLE_OFFLINE_PAGES) #if BUILDFLAG(ENABLE_OFFLINE_PAGES)
offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents); offline_pages::OfflinePageTabHelper::CreateForWebContents(web_contents);
offline_pages::RecentTabHelper::CreateForWebContents(web_contents); offline_pages::RecentTabHelper::CreateForWebContents(web_contents);
offline_pages::AutoFetchPageLoadWatcher::CreateForWebContents(web_contents);
#endif #endif
#if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION) #if BUILDFLAG(ENABLE_CAPTIVE_PORTAL_DETECTION)
......
...@@ -2968,6 +2968,7 @@ test("unit_tests") { ...@@ -2968,6 +2968,7 @@ test("unit_tests") {
if (enable_offline_pages) { if (enable_offline_pages) {
sources += [ sources += [
"../browser/offline_pages/auto_fetch_page_load_watcher_unittest.cc",
"../browser/offline_pages/background_loader_offliner_unittest.cc", "../browser/offline_pages/background_loader_offliner_unittest.cc",
"../browser/offline_pages/download_archive_manager_unittest.cc", "../browser/offline_pages/download_archive_manager_unittest.cc",
"../browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc", "../browser/offline_pages/offline_page_auto_fetcher_service_unittest.cc",
......
...@@ -88,14 +88,40 @@ void RequestCoordinatorStubTaco::SetRequestCoordinatorDelegate( ...@@ -88,14 +88,40 @@ void RequestCoordinatorStubTaco::SetRequestCoordinatorDelegate(
} }
void RequestCoordinatorStubTaco::CreateRequestCoordinator() { void RequestCoordinatorStubTaco::CreateRequestCoordinator() {
request_coordinator_ = std::make_unique<RequestCoordinator>( CHECK(!request_coordinator_)
<< "CreateRequestCoordinator can be called only once";
owned_request_coordinator_ = std::make_unique<RequestCoordinator>(
std::move(policy_), std::move(offliner_), std::move(queue_), std::move(policy_), std::move(offliner_), std::move(queue_),
std::move(scheduler_), network_quality_tracker_.get(), std::move(scheduler_), network_quality_tracker_.get(),
std::move(ukm_reporter_), std::move(active_tab_info_)); std::move(ukm_reporter_), std::move(active_tab_info_));
request_coordinator_ = owned_request_coordinator_.get();
} }
RequestCoordinator* RequestCoordinatorStubTaco::request_coordinator() { RequestCoordinator* RequestCoordinatorStubTaco::request_coordinator() {
CHECK(request_coordinator_); CHECK(request_coordinator_);
return request_coordinator_.get(); return request_coordinator_;
} }
base::RepeatingCallback<std::unique_ptr<KeyedService>(content::BrowserContext*)>
RequestCoordinatorStubTaco::FactoryFunction() {
return base::BindRepeating(
&RequestCoordinatorStubTaco::InternalFactoryFunction, GetWeakPtr());
}
// static
std::unique_ptr<KeyedService>
RequestCoordinatorStubTaco::InternalFactoryFunction(
base::WeakPtr<RequestCoordinatorStubTaco> taco,
content::BrowserContext* context) {
if (!taco)
return nullptr;
// Call CreateRequestCoordinator if it hasn't already been called.
if (!taco->request_coordinator_) {
taco->CreateRequestCoordinator();
}
// This function can only be used once.
CHECK(taco->owned_request_coordinator_);
return std::move(taco->owned_request_coordinator_);
}
} // namespace offline_pages } // namespace offline_pages
...@@ -14,6 +14,9 @@ ...@@ -14,6 +14,9 @@
#include "components/offline_pages/core/background/request_queue_store.h" #include "components/offline_pages/core/background/request_queue_store.h"
#include "components/offline_pages/core/background/scheduler.h" #include "components/offline_pages/core/background/scheduler.h"
namespace content {
class BrowserContext;
}
namespace network { namespace network {
class NetworkQualityTracker; class NetworkQualityTracker;
} }
...@@ -57,7 +60,21 @@ class RequestCoordinatorStubTaco { ...@@ -57,7 +60,21 @@ class RequestCoordinatorStubTaco {
RequestCoordinator* request_coordinator(); RequestCoordinator* request_coordinator();
// A factory function that can be used with
// RequestCoordinatorFactory::SetTestingFactoryAndUse.
base::RepeatingCallback<
std::unique_ptr<KeyedService>(content::BrowserContext*)>
FactoryFunction();
private: private:
base::WeakPtr<RequestCoordinatorStubTaco> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
static std::unique_ptr<KeyedService> InternalFactoryFunction(
base::WeakPtr<RequestCoordinatorStubTaco> taco,
content::BrowserContext*);
bool store_overridden_ = false; bool store_overridden_ = false;
bool queue_overridden_ = false; bool queue_overridden_ = false;
...@@ -69,7 +86,12 @@ class RequestCoordinatorStubTaco { ...@@ -69,7 +86,12 @@ class RequestCoordinatorStubTaco {
std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_; std::unique_ptr<OfflinePagesUkmReporter> ukm_reporter_;
std::unique_ptr<RequestCoordinator::ActiveTabInfo> active_tab_info_; std::unique_ptr<RequestCoordinator::ActiveTabInfo> active_tab_info_;
std::unique_ptr<RequestCoordinator> request_coordinator_; // This is null if the request coordinator was given to the
// RequestCoordinatorFactory through the factory function.
std::unique_ptr<RequestCoordinator> owned_request_coordinator_;
RequestCoordinator* request_coordinator_ = nullptr;
base::WeakPtrFactory<RequestCoordinatorStubTaco> weak_ptr_factory_{this};
}; };
} // namespace offline_pages } // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_REQUEST_COORDINATOR_STUB_TACO_H_ #endif // COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_REQUEST_COORDINATOR_STUB_TACO_H_
...@@ -260,6 +260,8 @@ class RenderViewHostTestHarness : public testing::Test { ...@@ -260,6 +260,8 @@ class RenderViewHostTestHarness : public testing::Test {
// context. // context.
virtual BrowserContext* GetBrowserContext(); virtual BrowserContext* GetBrowserContext();
TestBrowserThreadBundle* thread_bundle() { return thread_bundle_.get(); }
#if defined(USE_AURA) #if defined(USE_AURA)
aura::Window* root_window() { return aura_test_helper_->root_window(); } aura::Window* root_window() { return aura_test_helper_->root_window(); }
#endif #endif
......
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