blob: ccfc2713844ed315283a4202b6c1502cc9590c0e [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "extensions/common/api/declarative_net_request/test_utils.h"
#include <utility>
#include "base/files/file_util.h"
#include "base/json/json_file_value_serializer.h"
#include "extensions/common/api/declarative_net_request.h"
#include "extensions/common/constants.h"
#include "extensions/common/manifest_constants.h"
namespace extensions {
namespace keys = manifest_keys;
namespace dnr_api = api::declarative_net_request;
namespace declarative_net_request {
namespace {
const base::FilePath::CharType kBackgroundScriptFilepath[] =
FILE_PATH_LITERAL("background.js");
base::Value ToValue(const std::string& t) {
return base::Value(t);
}
base::Value ToValue(int t) {
return base::Value(t);
}
base::Value ToValue(bool t) {
return base::Value(t);
}
base::Value ToValue(const DictionarySource& source) {
return base::Value(source.ToValue());
}
base::Value ToValue(const TestRulesetInfo& info) {
return base::Value(info.GetManifestValue());
}
template <typename T>
base::Value::List ToValue(const std::vector<T>& vec) {
base::Value::List builder;
for (const T& t : vec)
builder.Append(ToValue(t));
return builder;
}
template <typename T>
void SetValue(base::Value::Dict& dict,
const char* key,
const std::optional<T>& value) {
if (!value)
return;
dict.Set(key, ToValue(*value));
}
} // namespace
TestRuleCondition::TestRuleCondition() = default;
TestRuleCondition::~TestRuleCondition() = default;
TestRuleCondition::TestRuleCondition(const TestRuleCondition&) = default;
TestRuleCondition& TestRuleCondition::operator=(const TestRuleCondition&) =
default;
base::Value::Dict TestRuleCondition::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kUrlFilterKey, url_filter);
SetValue(dict, kRegexFilterKey, regex_filter);
SetValue(dict, kIsUrlFilterCaseSensitiveKey, is_url_filter_case_sensitive);
SetValue(dict, kDomainsKey, domains);
SetValue(dict, kExcludedDomainsKey, excluded_domains);
SetValue(dict, kInitiatorDomainsKey, initiator_domains);
SetValue(dict, kExcludedInitiatorDomainsKey, excluded_initiator_domains);
SetValue(dict, kRequestDomainsKey, request_domains);
SetValue(dict, kExcludedRequestDomainsKey, excluded_request_domains);
SetValue(dict, kRequestMethodsKey, request_methods);
SetValue(dict, kExcludedRequestMethodsKey, excluded_request_methods);
SetValue(dict, kResourceTypesKey, resource_types);
SetValue(dict, kExcludedResourceTypesKey, excluded_resource_types);
SetValue(dict, kTabIdsKey, tab_ids);
SetValue(dict, kExcludedTabIdsKey, excluded_tab_ids);
SetValue(dict, kDomainTypeKey, domain_type);
SetValue(dict, kResponseHeadersKey, response_headers);
SetValue(dict, kExcludedResponseHeadersKey, excluded_response_headers);
return dict;
}
TestRuleQueryKeyValue::TestRuleQueryKeyValue() = default;
TestRuleQueryKeyValue::~TestRuleQueryKeyValue() = default;
TestRuleQueryKeyValue::TestRuleQueryKeyValue(const TestRuleQueryKeyValue&) =
default;
TestRuleQueryKeyValue& TestRuleQueryKeyValue::operator=(
const TestRuleQueryKeyValue&) = default;
base::Value::Dict TestRuleQueryKeyValue::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kQueryKeyKey, key);
SetValue(dict, kQueryValueKey, value);
SetValue(dict, kQueryReplaceOnlyKey, replace_only);
return dict;
}
TestRuleQueryTransform::TestRuleQueryTransform() = default;
TestRuleQueryTransform::~TestRuleQueryTransform() = default;
TestRuleQueryTransform::TestRuleQueryTransform(const TestRuleQueryTransform&) =
default;
TestRuleQueryTransform& TestRuleQueryTransform::operator=(
const TestRuleQueryTransform&) = default;
base::Value::Dict TestRuleQueryTransform::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kQueryTransformRemoveParamsKey, remove_params);
SetValue(dict, kQueryTransformAddReplaceParamsKey, add_or_replace_params);
return dict;
}
TestRuleTransform::TestRuleTransform() = default;
TestRuleTransform::~TestRuleTransform() = default;
TestRuleTransform::TestRuleTransform(const TestRuleTransform&) = default;
TestRuleTransform& TestRuleTransform::operator=(const TestRuleTransform&) =
default;
base::Value::Dict TestRuleTransform::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kTransformSchemeKey, scheme);
SetValue(dict, kTransformHostKey, host);
SetValue(dict, kTransformPortKey, port);
SetValue(dict, kTransformPathKey, path);
SetValue(dict, kTransformQueryKey, query);
SetValue(dict, kTransformQueryTransformKey, query_transform);
SetValue(dict, kTransformFragmentKey, fragment);
SetValue(dict, kTransformUsernameKey, username);
SetValue(dict, kTransformPasswordKey, password);
return dict;
}
TestRuleRedirect::TestRuleRedirect() = default;
TestRuleRedirect::~TestRuleRedirect() = default;
TestRuleRedirect::TestRuleRedirect(const TestRuleRedirect&) = default;
TestRuleRedirect& TestRuleRedirect::operator=(const TestRuleRedirect&) =
default;
base::Value::Dict TestRuleRedirect::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kExtensionPathKey, extension_path);
SetValue(dict, kTransformKey, transform);
SetValue(dict, kRedirectUrlKey, url);
SetValue(dict, kRegexSubstitutionKey, regex_substitution);
return dict;
}
TestHeaderInfo::TestHeaderInfo(std::string header,
std::string operation,
std::optional<std::string> value)
: header(std::move(header)),
operation(std::move(operation)),
value(std::move(value)) {}
TestHeaderInfo::~TestHeaderInfo() = default;
TestHeaderInfo::TestHeaderInfo(const TestHeaderInfo&) = default;
TestHeaderInfo& TestHeaderInfo::operator=(const TestHeaderInfo&) = default;
base::Value::Dict TestHeaderInfo::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kHeaderNameKey, header);
SetValue(dict, kHeaderOperationKey, operation);
SetValue(dict, kHeaderValueKey, value);
return dict;
}
TestHeaderCondition::TestHeaderCondition(
std::string header,
std::vector<std::string> values,
std::vector<std::string> excluded_values)
: header(std::move(header)),
values(std::move(values)),
excluded_values(std::move(excluded_values)) {}
TestHeaderCondition::~TestHeaderCondition() = default;
TestHeaderCondition::TestHeaderCondition(const TestHeaderCondition&) = default;
TestHeaderCondition& TestHeaderCondition::operator=(
const TestHeaderCondition&) = default;
base::Value::Dict TestHeaderCondition::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kHeaderNameKey, header);
SetValue(dict, kHeaderValuesKey, values);
SetValue(dict, kHeaderExcludedValuesKey, excluded_values);
return dict;
}
TestRuleAction::TestRuleAction() = default;
TestRuleAction::~TestRuleAction() = default;
TestRuleAction::TestRuleAction(const TestRuleAction&) = default;
TestRuleAction& TestRuleAction::operator=(const TestRuleAction&) = default;
base::Value::Dict TestRuleAction::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kRuleActionTypeKey, type);
SetValue(dict, kRequestHeadersKey, request_headers);
SetValue(dict, kResponseHeadersKey, response_headers);
SetValue(dict, kRedirectKey, redirect);
return dict;
}
TestRule::TestRule() = default;
TestRule::~TestRule() = default;
TestRule::TestRule(const TestRule&) = default;
TestRule& TestRule::operator=(const TestRule&) = default;
base::Value::Dict TestRule::ToValue() const {
base::Value::Dict dict;
SetValue(dict, kIDKey, id);
SetValue(dict, kPriorityKey, priority);
SetValue(dict, kRuleConditionKey, condition);
SetValue(dict, kRuleActionKey, action);
return dict;
}
TestRule CreateGenericRule(int id) {
TestRuleCondition condition;
condition.url_filter = std::string("filter");
TestRuleAction action;
action.type = std::string("block");
TestRule rule;
rule.id = id;
rule.priority = kMinValidPriority;
rule.action = action;
rule.condition = condition;
return rule;
}
TestRule CreateRegexRule(int id) {
TestRule rule = CreateGenericRule(id);
rule.condition->url_filter.reset();
rule.condition->regex_filter = std::string("filter");
return rule;
}
TestRulesetInfo::TestRulesetInfo(const std::string& manifest_id_and_path,
base::Value::List rules_value,
bool enabled)
: TestRulesetInfo(manifest_id_and_path,
manifest_id_and_path,
std::move(rules_value),
enabled) {}
TestRulesetInfo::TestRulesetInfo(const std::string& manifest_id,
const std::string& relative_file_path,
base::Value::List rules_value,
bool enabled)
: manifest_id(manifest_id),
relative_file_path(relative_file_path),
rules_value(std::move(rules_value)),
enabled(enabled) {}
TestRulesetInfo::TestRulesetInfo(const std::string& manifest_id,
const std::string& relative_file_path,
const base::Value& rules_value,
bool enabled)
: manifest_id(manifest_id),
relative_file_path(relative_file_path),
rules_value(rules_value.Clone()),
enabled(enabled) {}
TestRulesetInfo::TestRulesetInfo(const TestRulesetInfo& info)
: TestRulesetInfo(info.manifest_id,
info.relative_file_path,
info.rules_value.Clone(),
info.enabled) {}
base::Value::Dict TestRulesetInfo::GetManifestValue() const {
dnr_api::Ruleset ruleset;
ruleset.id = manifest_id;
ruleset.path = relative_file_path;
ruleset.enabled = enabled;
return ruleset.ToValue();
}
base::Value::Dict CreateManifest(
const std::vector<TestRulesetInfo>& ruleset_info,
const std::vector<std::string>& hosts,
unsigned flags,
const std::string& extension_name) {
std::vector<std::string> permissions = hosts;
if (!(flags & kConfig_OmitDeclarativeNetRequestPermission))
permissions.push_back(kDeclarativeNetRequestPermission);
// These permissions are needed for some tests. TODO(karandeepb): Add a
// ConfigFlag for these.
permissions.push_back("webRequest");
permissions.push_back("webRequestBlocking");
if (flags & kConfig_HasFeedbackPermission)
permissions.push_back(kFeedbackAPIPermission);
if (flags & kConfig_HasActiveTab)
permissions.push_back("activeTab");
if (flags & kConfig_HasDelarativeNetRequestWithHostAccessPermission)
permissions.push_back("declarativeNetRequestWithHostAccess");
std::vector<std::string> background_scripts;
if (flags & kConfig_HasBackgroundScript)
background_scripts.push_back("background.js");
base::Value::Dict manifest_builder;
if (flags & kConfig_OmitDeclarativeNetRequestKey) {
DCHECK(ruleset_info.empty());
} else {
manifest_builder.Set(
dnr_api::ManifestKeys::kDeclarativeNetRequest,
base::Value::Dict().Set(dnr_api::DNRInfo::kRuleResources,
ToValue(ruleset_info)));
}
if (flags & kConfig_HasManifestSandbox) {
manifest_builder.SetByDottedPath(
keys::kSandboxedPages,
base::Value::List().Append(kManifestSandboxPageFilepath));
}
// std::move() to trigger rvalue overloads.
return std::move(manifest_builder)
.Set(keys::kName, extension_name)
.Set(keys::kPermissions, ToValue(permissions))
.Set(keys::kVersion, "1.0")
.Set(keys::kManifestVersion, 2)
.Set("background",
base::Value::Dict().Set("scripts", ToValue(background_scripts)))
.Set(keys::kBrowserAction, base::Value::Dict());
}
base::Value::List ToListValue(const std::vector<std::string>& vec) {
return ToValue(vec);
}
base::Value::List ToListValue(const std::vector<TestRule>& rules) {
return ToValue(rules);
}
void WriteManifestAndRulesets(const base::FilePath& extension_dir,
const std::vector<TestRulesetInfo>& ruleset_info,
const std::vector<std::string>& hosts,
unsigned flags,
const std::string& extension_name) {
// Persist JSON rules files.
for (const TestRulesetInfo& info : ruleset_info) {
JSONFileValueSerializer(extension_dir.AppendASCII(info.relative_file_path))
.Serialize(info.rules_value);
}
// Persist a background script if needed.
if (flags & ConfigFlag::kConfig_HasBackgroundScript) {
static constexpr char kScriptWithOnUpdateAvailable[] =
"chrome.runtime.onUpdateAvailable.addListener(() => {});"
"chrome.test.sendMessage('ready');";
std::string content = flags & ConfigFlag::kConfig_ListenForOnUpdateAvailable
? kScriptWithOnUpdateAvailable
: "chrome.test.sendMessage('ready');";
CHECK(base::WriteFile(extension_dir.Append(kBackgroundScriptFilepath),
content));
}
// Persist a manifest sandbox page if needed.
if (flags & ConfigFlag::kConfig_HasManifestSandbox) {
static constexpr char kManifestSandboxPage[] = "<html></html>";
CHECK(
base::WriteFile(extension_dir.AppendASCII(kManifestSandboxPageFilepath),
kManifestSandboxPage));
}
// Persist manifest file.
JSONFileValueSerializer(extension_dir.Append(kManifestFilename))
.Serialize(CreateManifest(ruleset_info, hosts, flags, extension_name));
}
void WriteManifestAndRuleset(const base::FilePath& extension_dir,
const TestRulesetInfo& info,
const std::vector<std::string>& hosts,
unsigned flags,
const std::string& extension_name) {
WriteManifestAndRulesets(extension_dir, {info}, hosts, flags, extension_name);
}
} // namespace declarative_net_request
} // namespace extensions