blob: 4310e81c62dc1b7cc2cf0b21b2e0884b04ae6454 [file] [log] [blame]
// 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/browser_switcher/browser_switcher_service.h"
#include <string>
#include <utility>
#include "base/bind.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"
#include "chrome/browser/browser_switcher/ieem_sitelist_parser.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
namespace browser_switcher {
namespace {
// How long to wait after |BrowserSwitcherService| is created before initiating
// the sitelist fetch.
const base::TimeDelta kFetchSitelistDelay = base::TimeDelta::FromSeconds(60);
// How many times to re-try fetching the XML file for the sitelist.
const int kFetchNumRetries = 1;
// TODO(nicolaso): Add chrome_policy for this annotation once the policy is
// implemented.
constexpr net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("browser_switcher_ieem_sitelist", R"(
semantics {
sender: "Browser Switcher"
description:
"BrowserSwitcher may download Internet Explorer's Enterprise Mode "
"SiteList XML, to load the list of URLs to open in an alternative "
"browser. This is often on the organization's intranet.For more "
"information on Internet Explorer's Enterprise Mode, see: "
"https://docs.microsoft.com/internet-explorer/ie11-deploy-guide"
"/what-is-enterprise-mode"
trigger:
"This happens only once per profile, 60s after the first page "
"starts loading. The request may be retried once if it failed the "
"first time."
data:
"Up to 2 (plus retries) HTTP or HTTPS GET requests to the URLs "
"configured in Internet Explorer's SiteList policy, and Chrome's "
"BrowserSwitcherExternalSitelistUrl policy."
destination: OTHER
destination_other:
"URL configured in Internet Explorer's SiteList policy, and URL "
"configured in Chrome's BrowserSwitcherExternalSitelistUrl policy. "
}
policy {
cookies_allowed: NO
setting: "This feature cannot be disabled by settings."
policy_exception_justification:
"This feature still in development, and is disabled by default. "
"It needs to be enabled through policies."
})");
} // namespace
XmlDownloader::XmlDownloader(Profile* profile,
GURL url,
base::TimeDelta delay,
base::OnceCallback<void(ParsedXml)> done_callback)
: url_(std::move(url)),
done_callback_(std::move(done_callback)),
weak_ptr_factory_(this) {
factory_ = content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess();
DCHECK(factory_);
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&XmlDownloader::FetchXml, weak_ptr_factory_.GetWeakPtr()),
delay);
}
XmlDownloader::~XmlDownloader() = default;
void XmlDownloader::FetchXml() {
auto request = std::make_unique<network::ResourceRequest>();
request->url = url_;
request->load_flags =
(net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
net::LOAD_DISABLE_CACHE);
url_loader_ =
network::SimpleURLLoader::Create(std::move(request), traffic_annotation);
url_loader_->SetRetryOptions(
kFetchNumRetries,
network::SimpleURLLoader::RetryMode::RETRY_ON_NETWORK_CHANGE);
url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
factory_.get(),
base::BindOnce(&XmlDownloader::ParseXml, weak_ptr_factory_.GetWeakPtr()));
}
void XmlDownloader::ParseXml(std::unique_ptr<std::string> bytes) {
if (!bytes) {
DoneParsing(ParsedXml({}, {}, "could not fetch XML"));
return;
}
ParseIeemXml(*bytes, base::BindOnce(&XmlDownloader::DoneParsing,
weak_ptr_factory_.GetWeakPtr()));
}
void XmlDownloader::DoneParsing(ParsedXml xml) {
factory_.reset();
url_loader_.reset();
std::move(done_callback_).Run(std::move(xml));
}
BrowserSwitcherService::BrowserSwitcherService(Profile* profile)
: prefs_(profile->GetPrefs()),
driver_(new AlternativeBrowserDriverImpl(&prefs_)),
sitelist_(new BrowserSwitcherSitelistImpl(&prefs_)),
weak_ptr_factory_(this) {
GURL external_url = prefs_.GetExternalSitelistUrl();
if (external_url.is_valid()) {
external_sitelist_downloader_ = std::make_unique<XmlDownloader>(
profile, std::move(external_url), fetch_delay_,
base::BindOnce(&BrowserSwitcherService::OnExternalSitelistParsed,
weak_ptr_factory_.GetWeakPtr()));
}
}
BrowserSwitcherService::~BrowserSwitcherService() {}
AlternativeBrowserDriver* BrowserSwitcherService::driver() {
return driver_.get();
}
BrowserSwitcherSitelist* BrowserSwitcherService::sitelist() {
return sitelist_.get();
}
const BrowserSwitcherPrefs& BrowserSwitcherService::prefs() const {
return prefs_;
}
void BrowserSwitcherService::SetDriverForTesting(
std::unique_ptr<AlternativeBrowserDriver> driver) {
driver_ = std::move(driver);
}
void BrowserSwitcherService::SetSitelistForTesting(
std::unique_ptr<BrowserSwitcherSitelist> sitelist) {
sitelist_ = std::move(sitelist);
}
void BrowserSwitcherService::OnExternalSitelistParsed(ParsedXml xml) {
if (xml.error) {
LOG(ERROR) << "Unable to parse IEEM SiteList: " << *xml.error;
} else {
VLOG(2) << "Done parsing external SiteList. "
<< "Applying rules to future navigations.";
sitelist()->SetExternalSitelist(std::move(xml));
}
external_sitelist_downloader_.reset();
}
base::TimeDelta BrowserSwitcherService::fetch_delay_ = kFetchSitelistDelay;
// static
void BrowserSwitcherService::SetFetchDelayForTesting(base::TimeDelta delay) {
fetch_delay_ = delay;
}
} // namespace browser_switcher