Commit 23afdc6d authored by Nicolas's avatar Nicolas Committed by Commit Bot

BrowserSwitcherService: split implementation between platforms

This CL adds BrowserSwitcherServiceWin, which extends
BrowserSwitcherService and contains the Windows-specific code. This
avoids too many #ifdefs in that file.

Change-Id: Icbf49f82e605710c273c8795805c4ad962b67ea7
Reviewed-on: https://chromium-review.googlesource.com/c/1457221Reviewed-by: default avatarJulian Pastarmov <pastarmovj@chromium.org>
Commit-Queue: Nicolas Ouellet-Payeur <nicolaso@chromium.org>
Cr-Commit-Position: refs/heads/master@{#629945}
parent 6dbe9498
......@@ -3410,6 +3410,8 @@ jumbo_split_static_library("browser") {
sources += [
"badging/badge_manager_delegate_win.cc",
"badging/badge_manager_delegate_win.h",
"browser_switcher/browser_switcher_service_win.cc",
"browser_switcher/browser_switcher_service_win.h",
"downgrade/user_data_downgrade.cc",
"downgrade/user_data_downgrade.h",
"first_run/upgrade_util.cc",
......
......@@ -4,13 +4,10 @@
#include "chrome/browser/browser_switcher/browser_switcher_service.h"
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "build/build_config.h"
#include "chrome/browser/browser_switcher/alternative_browser_driver.h"
#include "chrome/browser/browser_switcher/browser_switcher_prefs.h"
#include "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
......@@ -21,30 +18,11 @@
#include "content/public/browser/storage_partition.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/simple_url_loader.h"
#if defined(OS_WIN)
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/win/registry.h"
#endif
namespace browser_switcher {
namespace {
#if defined(OS_WIN)
const wchar_t kIeSiteListKey[] =
L"SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main\\EnterpriseMode";
const wchar_t kIeSiteListValue[] = L"SiteList";
#endif
// How long to wait after |BrowserSwitcherService| is created before initiating
// the sitelist fetch.
const base::TimeDelta kFetchSitelistDelay = base::TimeDelta::FromSeconds(60);
......@@ -86,101 +64,8 @@ constexpr net::NetworkTrafficAnnotationTag traffic_annotation =
"It needs to be enabled through policies."
})");
#if defined(OS_WIN)
const int kCurrentFileVersion = 1;
base::FilePath GetCacheDir() {
base::FilePath path;
if (!base::PathService::Get(base::DIR_LOCAL_APP_DATA, &path))
return path;
path = path.AppendASCII("Google");
path = path.AppendASCII("BrowserSwitcher");
return path;
}
// Serialize prefs to a string for writing to cache.dat.
std::string SerializeCacheFile(const BrowserSwitcherPrefs& prefs) {
std::ostringstream buffer;
buffer << kCurrentFileVersion << std::endl;
buffer << prefs.GetAlternativeBrowserPath() << std::endl;
buffer << base::JoinString(prefs.GetAlternativeBrowserParameters(), " ")
<< std::endl;
// TODO(nicolaso): Use GetChromePath() and GetChromeParameters once the
// policies are implemented. For now, those are just ${chrome} with no
// arguments, to ensure the BHO works correctly.
buffer << "${chrome}" << std::endl;
buffer << base::JoinString(std::vector<std::string>(), " ") << std::endl;
const auto& rules = prefs.GetRules();
buffer << rules.sitelist.size() << std::endl;
if (!rules.sitelist.empty())
buffer << base::JoinString(rules.sitelist, "\n") << std::endl;
buffer << rules.greylist.size() << std::endl;
if (!rules.greylist.empty())
buffer << base::JoinString(rules.greylist, "\n") << std::endl;
return buffer.str();
}
void SavePrefsToFile(std::string data) {
// Ensure the directory exists
base::FilePath dir = GetCacheDir();
bool success = base::CreateDirectory(dir);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MkDirSuccess", success);
if (!success) {
LOG(ERROR) << "Could not create directory: " << dir.LossyDisplayName();
return;
}
base::FilePath tmp_path;
success = base::CreateTemporaryFileInDir(dir, &tmp_path);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MkTempSuccess", success);
if (!success) {
LOG(ERROR) << "Could not open file for writing: "
<< tmp_path.LossyDisplayName();
return;
}
base::WriteFile(tmp_path, data.c_str(), data.size());
base::FilePath dest_path = dir.AppendASCII("cache.dat");
success = base::Move(tmp_path, dest_path);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MoveSuccess", success);
}
#endif
} // namespace
class XmlDownloader {
public:
// Posts a task to start downloading+parsing the rules after |delay|. Calls
// |done_callback| when done, so the caller can apply the parsed rules and
// clean up this object.
XmlDownloader(Profile* profile,
GURL url,
base::TimeDelta delay,
base::OnceCallback<void(ParsedXml)> done_callback);
virtual ~XmlDownloader() = default;
private:
void FetchXml();
void ParseXml(std::unique_ptr<std::string> bytes);
void DoneParsing(ParsedXml xml);
GURL url_;
scoped_refptr<network::SharedURLLoaderFactory> factory_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
base::OnceCallback<void(ParsedXml)> done_callback_;
base::WeakPtrFactory<XmlDownloader> weak_ptr_factory_;
};
XmlDownloader::XmlDownloader(Profile* profile,
GURL url,
base::TimeDelta delay,
......@@ -197,6 +82,8 @@ XmlDownloader::XmlDownloader(Profile* profile,
delay);
}
XmlDownloader::~XmlDownloader() = default;
void XmlDownloader::FetchXml() {
auto request = std::make_unique<network::ResourceRequest>();
request->url = url_;
......@@ -240,30 +127,6 @@ BrowserSwitcherService::BrowserSwitcherService(Profile* profile)
base::BindOnce(&BrowserSwitcherService::OnExternalSitelistParsed,
weak_ptr_factory_.GetWeakPtr()));
}
#if defined(OS_WIN)
if (prefs_.UseIeSitelist()) {
GURL sitelist_url = GetIeemSitelistUrl();
if (sitelist_url.is_valid()) {
ieem_downloader_ = std::make_unique<XmlDownloader>(
profile, std::move(sitelist_url), fetch_delay_,
base::BindOnce(&BrowserSwitcherService::OnIeemSitelistParsed,
weak_ptr_factory_.GetWeakPtr()));
}
}
if (prefs_.IsEnabled()) {
// TODO(nicolaso): also write cache.dat when policies change (e.g. after
// loading cloud policies or after enabling LBS while Chrome is running).
//
// Write the cache.dat file.
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(&SavePrefsToFile, SerializeCacheFile(prefs_)));
}
#endif
}
BrowserSwitcherService::~BrowserSwitcherService() {}
......@@ -308,42 +171,4 @@ void BrowserSwitcherService::SetFetchDelayForTesting(base::TimeDelta delay) {
fetch_delay_ = delay;
}
#if defined(OS_WIN)
base::Optional<std::string>
BrowserSwitcherService::ieem_sitelist_url_for_testing_;
// static
void BrowserSwitcherService::SetIeemSitelistUrlForTesting(
const std::string& spec) {
ieem_sitelist_url_for_testing_ = spec;
}
// static
GURL BrowserSwitcherService::GetIeemSitelistUrl() {
if (ieem_sitelist_url_for_testing_ != base::nullopt)
return GURL(*ieem_sitelist_url_for_testing_);
base::win::RegKey key;
if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, kIeSiteListKey, KEY_READ) &&
ERROR_SUCCESS != key.Open(HKEY_CURRENT_USER, kIeSiteListKey, KEY_READ)) {
return GURL();
}
std::wstring url_string;
if (ERROR_SUCCESS != key.ReadValue(kIeSiteListValue, &url_string))
return GURL();
return GURL(base::UTF16ToUTF8(url_string));
}
void BrowserSwitcherService::OnIeemSitelistParsed(ParsedXml xml) {
if (xml.error) {
LOG(ERROR) << "Unable to parse IEEM SiteList: " << *xml.error;
} else {
VLOG(2) << "Done parsing IEEM SiteList. "
<< "Applying rules to future navigations.";
sitelist()->SetIeemSitelist(std::move(xml));
}
ieem_downloader_.reset();
}
#endif
} // namespace browser_switcher
......@@ -16,6 +16,8 @@
#include "build/build_config.h"
#include "chrome/browser/browser_switcher/browser_switcher_prefs.h"
#include "components/keyed_service/core/keyed_service.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "url/gurl.h"
class Profile;
......@@ -25,7 +27,31 @@ namespace browser_switcher {
class AlternativeBrowserDriver;
class BrowserSwitcherSitelist;
class ParsedXml;
class XmlDownloader;
class XmlDownloader {
public:
// Posts a task to start downloading+parsing the rules after |delay|. Calls
// |done_callback| when done, so the caller can apply the parsed rules and
// clean up this object.
XmlDownloader(Profile* profile,
GURL url,
base::TimeDelta delay,
base::OnceCallback<void(ParsedXml)> done_callback);
virtual ~XmlDownloader();
private:
void FetchXml();
void ParseXml(std::unique_ptr<std::string> bytes);
void DoneParsing(ParsedXml xml);
GURL url_;
scoped_refptr<network::SharedURLLoaderFactory> factory_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
base::OnceCallback<void(ParsedXml)> done_callback_;
base::WeakPtrFactory<XmlDownloader> weak_ptr_factory_;
};
// Manages per-profile resources for BrowserSwitcher.
class BrowserSwitcherService : public KeyedService {
......@@ -42,33 +68,16 @@ class BrowserSwitcherService : public KeyedService {
static void SetFetchDelayForTesting(base::TimeDelta delay);
#if defined(OS_WIN)
static void SetIeemSitelistUrlForTesting(const std::string& url);
#endif
private:
#if defined(OS_WIN)
// Returns the URL to fetch to get Internet Explorer's Enterprise Mode
// sitelist, based on policy. Returns an empty (invalid) URL if IE's SiteList
// policy is unset.
static GURL GetIeemSitelistUrl();
void OnIeemSitelistParsed(ParsedXml xml);
std::unique_ptr<XmlDownloader> ieem_downloader_;
// URL to fetch the IEEM sitelist from. Only used for testing.
static base::Optional<std::string> ieem_sitelist_url_for_testing_;
#endif
void OnExternalSitelistParsed(ParsedXml xml);
protected:
BrowserSwitcherPrefs prefs_;
// Delay for the IEEM/external XML fetch tasks, launched from the constructor.
static base::TimeDelta fetch_delay_;
std::unique_ptr<XmlDownloader> external_sitelist_downloader_;
private:
void OnExternalSitelistParsed(ParsedXml xml);
BrowserSwitcherPrefs prefs_;
std::unique_ptr<XmlDownloader> external_sitelist_downloader_;
// Per-profile helpers.
std::unique_ptr<AlternativeBrowserDriver> driver_;
......@@ -76,6 +85,7 @@ class BrowserSwitcherService : public KeyedService {
base::WeakPtrFactory<BrowserSwitcherService> weak_ptr_factory_;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserSwitcherService);
};
......
......@@ -23,6 +23,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include "chrome/browser/browser_switcher/browser_switcher_service_win.h"
#endif
namespace browser_switcher {
namespace {
......@@ -210,7 +214,7 @@ IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest,
#if defined(OS_WIN)
IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest, IeemSitelistInvalidUrl) {
SetUseIeSitelist(true);
BrowserSwitcherService::SetIeemSitelistUrlForTesting(kAnInvalidUrl);
BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(kAnInvalidUrl);
bool fetch_happened = false;
content::URLLoaderInterceptor interceptor(base::BindRepeating(
......@@ -241,7 +245,7 @@ IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest, IeemSitelistInvalidUrl) {
IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest,
IeemFetchAndParseAfterStartup) {
SetUseIeSitelist(true);
BrowserSwitcherService::SetIeemSitelistUrlForTesting(kAValidUrl);
BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(kAValidUrl);
content::URLLoaderInterceptor interceptor(
base::BindRepeating(ReturnValidXml));
......@@ -265,7 +269,7 @@ IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest,
IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest, IeemIgnoresFailedDownload) {
SetUseIeSitelist(true);
BrowserSwitcherService::SetIeemSitelistUrlForTesting(kAValidUrl);
BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(kAValidUrl);
content::URLLoaderInterceptor interceptor(
base::BindRepeating(FailToDownload));
......@@ -290,7 +294,7 @@ IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest, IeemIgnoresFailedDownload) {
IN_PROC_BROWSER_TEST_F(BrowserSwitcherServiceTest, IeemIgnoresNonManagedPref) {
browser()->profile()->GetPrefs()->SetBoolean(prefs::kUseIeSitelist, true);
BrowserSwitcherService::SetIeemSitelistUrlForTesting(kAValidUrl);
BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(kAValidUrl);
bool fetch_happened = false;
content::URLLoaderInterceptor interceptor(base::BindRepeating(
......
......@@ -4,6 +4,7 @@
#include "chrome/browser/browser_switcher/browser_switcher_service_factory.h"
#include "build/build_config.h"
#include "chrome/browser/browser_switcher/browser_switcher_service.h"
#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
......@@ -12,8 +13,22 @@
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#if defined(OS_WIN)
#include "chrome/browser/browser_switcher/browser_switcher_service_win.h"
#endif
namespace browser_switcher {
namespace {
#if defined(OS_WIN)
using BrowserSwitcherServiceImpl = BrowserSwitcherServiceWin;
#else
using BrowserSwitcherServiceImpl = BrowserSwitcherService;
#endif
} // namespace
// static
BrowserSwitcherServiceFactory* BrowserSwitcherServiceFactory::GetInstance() {
return base::Singleton<BrowserSwitcherServiceFactory>::get();
......@@ -35,7 +50,7 @@ BrowserSwitcherServiceFactory::~BrowserSwitcherServiceFactory() {}
KeyedService* BrowserSwitcherServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new BrowserSwitcherService(Profile::FromBrowserContext(context));
return new BrowserSwitcherServiceImpl(Profile::FromBrowserContext(context));
}
content::BrowserContext* BrowserSwitcherServiceFactory::GetBrowserContextToUse(
......
// Copyright 2019 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/browser_switcher/browser_switcher_service_win.h"
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/win/registry.h"
#include "chrome/browser/browser_switcher/browser_switcher_prefs.h"
#include "chrome/browser/browser_switcher/browser_switcher_sitelist.h"
#include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
#include "chrome/browser/profiles/profile.h"
namespace browser_switcher {
namespace {
const wchar_t kIeSiteListKey[] =
L"SOFTWARE\\Policies\\Microsoft\\Internet Explorer\\Main\\EnterpriseMode";
const wchar_t kIeSiteListValue[] = L"SiteList";
const int kCurrentFileVersion = 1;
base::FilePath GetCacheDir() {
base::FilePath path;
if (!base::PathService::Get(base::DIR_LOCAL_APP_DATA, &path))
return path;
path = path.AppendASCII("Google");
path = path.AppendASCII("BrowserSwitcher");
return path;
}
// Serialize prefs to a string for writing to cache.dat.
std::string SerializeCacheFile(const BrowserSwitcherPrefs& prefs) {
std::ostringstream buffer;
buffer << kCurrentFileVersion << std::endl;
buffer << prefs.GetAlternativeBrowserPath() << std::endl;
buffer << base::JoinString(prefs.GetAlternativeBrowserParameters(), " ")
<< std::endl;
// TODO(nicolaso): Use GetChromePath() and GetChromeParameters once the
// policies are implemented. For now, those are just ${chrome} with no
// arguments, to ensure the BHO works correctly.
buffer << "${chrome}" << std::endl;
buffer << base::JoinString(std::vector<std::string>(), " ") << std::endl;
const auto& rules = prefs.GetRules();
buffer << rules.sitelist.size() << std::endl;
if (!rules.sitelist.empty())
buffer << base::JoinString(rules.sitelist, "\n") << std::endl;
buffer << rules.greylist.size() << std::endl;
if (!rules.greylist.empty())
buffer << base::JoinString(rules.greylist, "\n") << std::endl;
return buffer.str();
}
void SavePrefsToFile(std::string data) {
// Ensure the directory exists
base::FilePath dir = GetCacheDir();
bool success = base::CreateDirectory(dir);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MkDirSuccess", success);
if (!success) {
LOG(ERROR) << "Could not create directory: " << dir.LossyDisplayName();
return;
}
base::FilePath tmp_path;
success = base::CreateTemporaryFileInDir(dir, &tmp_path);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MkTempSuccess", success);
if (!success) {
LOG(ERROR) << "Could not open file for writing: "
<< tmp_path.LossyDisplayName();
return;
}
base::WriteFile(tmp_path, data.c_str(), data.size());
base::FilePath dest_path = dir.AppendASCII("cache.dat");
success = base::Move(tmp_path, dest_path);
UMA_HISTOGRAM_BOOLEAN("BrowserSwitcher.CacheFile.MoveSuccess", success);
}
} // namespace
BrowserSwitcherServiceWin::BrowserSwitcherServiceWin(Profile* profile)
: BrowserSwitcherService(profile), weak_ptr_factory_(this) {
if (prefs_.UseIeSitelist()) {
GURL sitelist_url = GetIeemSitelistUrl();
if (sitelist_url.is_valid()) {
ieem_downloader_ = std::make_unique<XmlDownloader>(
profile, std::move(sitelist_url), fetch_delay_,
base::BindOnce(&BrowserSwitcherServiceWin::OnIeemSitelistParsed,
weak_ptr_factory_.GetWeakPtr()));
}
}
if (prefs_.IsEnabled()) {
// TODO(nicolaso): also write cache.dat when policies change (e.g. after
// loading cloud policies or after enabling LBS while Chrome is running).
//
// Write the cache.dat file.
base::PostTaskWithTraits(
FROM_HERE,
{base::MayBlock(), base::TaskPriority::BEST_EFFORT,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(&SavePrefsToFile, SerializeCacheFile(prefs_)));
}
}
BrowserSwitcherServiceWin::~BrowserSwitcherServiceWin() = default;
base::Optional<std::string>
BrowserSwitcherServiceWin::ieem_sitelist_url_for_testing_;
// static
void BrowserSwitcherServiceWin::SetIeemSitelistUrlForTesting(
const std::string& spec) {
ieem_sitelist_url_for_testing_ = spec;
}
// static
GURL BrowserSwitcherServiceWin::GetIeemSitelistUrl() {
if (ieem_sitelist_url_for_testing_ != base::nullopt)
return GURL(*ieem_sitelist_url_for_testing_);
base::win::RegKey key;
if (ERROR_SUCCESS != key.Open(HKEY_LOCAL_MACHINE, kIeSiteListKey, KEY_READ) &&
ERROR_SUCCESS != key.Open(HKEY_CURRENT_USER, kIeSiteListKey, KEY_READ)) {
return GURL();
}
std::wstring url_string;
if (ERROR_SUCCESS != key.ReadValue(kIeSiteListValue, &url_string))
return GURL();
return GURL(base::UTF16ToUTF8(url_string));
}
void BrowserSwitcherServiceWin::OnIeemSitelistParsed(ParsedXml xml) {
if (xml.error) {
LOG(ERROR) << "Unable to parse IEEM SiteList: " << *xml.error;
} else {
VLOG(2) << "Done parsing IEEM SiteList. "
<< "Applying rules to future navigations.";
sitelist()->SetIeemSitelist(std::move(xml));
}
ieem_downloader_.reset();
}
} // namespace browser_switcher
// Copyright 2019 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_BROWSER_SWITCHER_BROWSER_SWITCHER_SERVICE_WIN_H_
#define CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_SERVICE_WIN_H_
#include <memory>
#include <string>
#include "base/optional.h"
#include "chrome/browser/browser_switcher/browser_switcher_service.h"
namespace browser_switcher {
// Windows-specific extension of BrowserSwitcherService.
class BrowserSwitcherServiceWin : public BrowserSwitcherService {
public:
explicit BrowserSwitcherServiceWin(Profile* profile);
~BrowserSwitcherServiceWin() override;
static void SetIeemSitelistUrlForTesting(const std::string& url);
private:
// Returns the URL to fetch to get Internet Explorer's Enterprise Mode
// sitelist, based on policy. Returns an empty (invalid) URL if IE's SiteList
// policy is unset.
static GURL GetIeemSitelistUrl();
void OnIeemSitelistParsed(ParsedXml xml);
std::unique_ptr<XmlDownloader> ieem_downloader_;
// URL to fetch the IEEM sitelist from. Only used for testing.
static base::Optional<std::string> ieem_sitelist_url_for_testing_;
base::WeakPtrFactory<BrowserSwitcherServiceWin> weak_ptr_factory_;
DISALLOW_IMPLICIT_CONSTRUCTORS(BrowserSwitcherServiceWin);
};
} // namespace browser_switcher
#endif // CHROME_BROWSER_BROWSER_SWITCHER_BROWSER_SWITCHER_SERVICE_WIN_H_
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