910e62b5创建于 1月15日历史提交
// 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.

#ifndef EXTENSIONS_COMMON_API_DECLARATIVE_NET_REQUEST_TEST_UTILS_H_
#define EXTENSIONS_COMMON_API_DECLARATIVE_NET_REQUEST_TEST_UTILS_H_

#include <optional>
#include <string>
#include <vector>

#include "base/files/file_path.h"
#include "base/values.h"
#include "extensions/common/api/declarative_net_request/constants.h"
#include "extensions/common/url_pattern.h"

namespace extensions::declarative_net_request {

inline constexpr char kManifestSandboxPageFilepath[] = "manifest_sandbox.html";

struct DictionarySource {
  DictionarySource() = default;
  virtual ~DictionarySource() = default;
  virtual base::Value::Dict ToValue() const = 0;
};

// Helper structs to simplify building base::Values which can later be used to
// serialize to JSON. The generated implementation for the JSON rules schema is
// not used since it's not flexible enough to generate the base::Value/JSON we
// want for tests.
struct TestHeaderCondition : public DictionarySource {
  TestHeaderCondition(std::string header,
                      std::vector<std::string> values,
                      std::vector<std::string> excluded_values);
  ~TestHeaderCondition() override;
  TestHeaderCondition(const TestHeaderCondition&);
  TestHeaderCondition& operator=(const TestHeaderCondition&);

  std::optional<std::string> header;
  std::optional<std::vector<std::string>> values;
  std::optional<std::vector<std::string>> excluded_values;

  base::Value::Dict ToValue() const override;
};

struct TestRuleCondition : public DictionarySource {
  TestRuleCondition();
  ~TestRuleCondition() override;
  TestRuleCondition(const TestRuleCondition&);
  TestRuleCondition& operator=(const TestRuleCondition&);

  std::optional<std::string> url_filter;
  std::optional<std::string> regex_filter;
  std::optional<bool> is_url_filter_case_sensitive;
  std::optional<std::vector<std::string>> domains;
  std::optional<std::vector<std::string>> excluded_domains;
  std::optional<std::vector<std::string>> initiator_domains;
  std::optional<std::vector<std::string>> excluded_initiator_domains;
  std::optional<std::vector<std::string>> request_domains;
  std::optional<std::vector<std::string>> excluded_request_domains;
  std::optional<std::vector<std::string>> top_domains;
  std::optional<std::vector<std::string>> excluded_top_domains;
  std::optional<std::vector<std::string>> request_methods;
  std::optional<std::vector<std::string>> excluded_request_methods;
  std::optional<std::vector<std::string>> resource_types;
  std::optional<std::vector<std::string>> excluded_resource_types;
  std::optional<std::vector<int>> tab_ids;
  std::optional<std::vector<int>> excluded_tab_ids;
  std::optional<std::string> domain_type;
  std::optional<std::vector<TestHeaderCondition>> response_headers;
  std::optional<std::vector<TestHeaderCondition>> excluded_response_headers;

  base::Value::Dict ToValue() const override;
};

struct TestRuleQueryKeyValue : public DictionarySource {
  TestRuleQueryKeyValue();
  ~TestRuleQueryKeyValue() override;
  TestRuleQueryKeyValue(const TestRuleQueryKeyValue&);
  TestRuleQueryKeyValue& operator=(const TestRuleQueryKeyValue&);

  std::optional<std::string> key;
  std::optional<std::string> value;
  std::optional<bool> replace_only;

  base::Value::Dict ToValue() const override;
};

struct TestRuleQueryTransform : public DictionarySource {
  TestRuleQueryTransform();
  ~TestRuleQueryTransform() override;
  TestRuleQueryTransform(const TestRuleQueryTransform&);
  TestRuleQueryTransform& operator=(const TestRuleQueryTransform&);

  std::optional<std::vector<std::string>> remove_params;
  std::optional<std::vector<TestRuleQueryKeyValue>> add_or_replace_params;

  base::Value::Dict ToValue() const override;
};

struct TestRuleTransform : public DictionarySource {
  TestRuleTransform();
  ~TestRuleTransform() override;
  TestRuleTransform(const TestRuleTransform&);
  TestRuleTransform& operator=(const TestRuleTransform&);

  std::optional<std::string> scheme;
  std::optional<std::string> host;
  std::optional<std::string> port;
  std::optional<std::string> path;
  std::optional<std::string> query;
  std::optional<TestRuleQueryTransform> query_transform;
  std::optional<std::string> fragment;
  std::optional<std::string> username;
  std::optional<std::string> password;

  base::Value::Dict ToValue() const override;
};

struct TestRuleRedirect : public DictionarySource {
  TestRuleRedirect();
  ~TestRuleRedirect() override;
  TestRuleRedirect(const TestRuleRedirect&);
  TestRuleRedirect& operator=(const TestRuleRedirect&);

  std::optional<std::string> extension_path;
  std::optional<TestRuleTransform> transform;
  std::optional<std::string> url;
  std::optional<std::string> regex_substitution;

  base::Value::Dict ToValue() const override;
};

struct TestHeaderInfo : public DictionarySource {
  TestHeaderInfo(std::string header,
                 std::string operation,
                 std::optional<std::string> value);
  ~TestHeaderInfo() override;
  TestHeaderInfo(const TestHeaderInfo&);
  TestHeaderInfo& operator=(const TestHeaderInfo&);

  std::optional<std::string> header;
  std::optional<std::string> operation;
  std::optional<std::string> value;

  base::Value::Dict ToValue() const override;
};

struct TestRuleAction : public DictionarySource {
  TestRuleAction();
  ~TestRuleAction() override;
  TestRuleAction(const TestRuleAction&);
  TestRuleAction& operator=(const TestRuleAction&);

  std::optional<std::string> type;
  std::optional<std::vector<TestHeaderInfo>> request_headers;
  std::optional<std::vector<TestHeaderInfo>> response_headers;
  std::optional<TestRuleRedirect> redirect;

  base::Value::Dict ToValue() const override;
};

struct TestRule : public DictionarySource {
  TestRule();
  ~TestRule() override;
  TestRule(const TestRule&);
  TestRule& operator=(const TestRule&);

  std::optional<int> id;
  std::optional<int> priority;
  std::optional<TestRuleCondition> condition;
  std::optional<TestRuleAction> action;

  base::Value::Dict ToValue() const override;
};

// Helper function to build a generic TestRule.
TestRule CreateGenericRule(int id = kMinValidID);

// Helper function to build a generic regex TestRule.
TestRule CreateRegexRule(int id = kMinValidID);

// Bitmasks to configure the extension under test.
enum ConfigFlag {
  kConfig_None = 0,

  // Whether a background script ("background.js") will be persisted for the
  // extension. Clients can listen in to the "ready" message from the background
  // page to detect its loading.
  kConfig_HasBackgroundScript = 1 << 0,

  // Whether the extension has the declarativeNetRequestFeedback permission.
  kConfig_HasFeedbackPermission = 1 << 1,

  // Whether the extension has the activeTab permission.
  kConfig_HasActiveTab = 1 << 2,

  // Whether the "declarative_net_request" manifest key should be omitted.
  kConfig_OmitDeclarativeNetRequestKey = 1 << 3,

  // Whether the "declarativeNetRequest" permission should be omitted.
  kConfig_OmitDeclarativeNetRequestPermission = 1 << 4,

  // Whether the "declarativeNetRequestWithHostAccess" permission should be
  // included.
  kConfig_HasDelarativeNetRequestWithHostAccessPermission = 1 << 5,

  // Whether the extension listens for the onUpdateAvailable event. This is
  // needed for an extension with a background script to receive delayed
  // updates.
  kConfig_ListenForOnUpdateAvailable = 1 << 6,

  // Whether the extension has an manifest sandbox page entry.
  kConfig_HasManifestSandbox = 1 << 7,

  // Whether the extension has a manifest action (popup) entry. This is needed
  // to activate chrome.action API.
  kConfig_HasAction = 1 << 8,

  // Whether the "webRequest" permission should be included.
  kConfig_HasWebRequestPermission = 1 << 9,

  // Whether the "webRequestBlocking" permission should be included. Requires
  // MV2 flag below.
  kConfig_DEPRECATED_HasWebRequestBlockingPermission = 1 << 10,

  // Whether to use deprecated Manifest Version 2.
  kConfig_DEPRECATED_ManifestVersion2 = 1 << 11,
};

// Describes a single extension ruleset.
struct TestRulesetInfo {
  TestRulesetInfo(const std::string& manifest_id_and_path,
                  base::Value::List rules_value,
                  bool enabled = true);
  TestRulesetInfo(const std::string& manifest_id,
                  const std::string& relative_file_path,
                  base::Value::List rules_value,
                  bool enabled = true);
  // Used to support the copy ctor, or to deliberately create `rules_value` of
  // the wrong type.
  TestRulesetInfo(const std::string& manifest_id,
                  const std::string& relative_file_path,
                  const base::Value& rules_value,
                  bool enabled = true);
  TestRulesetInfo(const TestRulesetInfo&);
  TestRulesetInfo& operator=(const TestRulesetInfo&);

  // Unique ID for the ruleset.
  const std::string manifest_id;

  // File path relative to the extension directory.
  const std::string relative_file_path;

  // The base::Value corresponding to the rules in the ruleset.
  const base::Value rules_value;

  // Whether the ruleset is enabled by default.
  const bool enabled;

  // Returns the corresponding value to be specified in the manifest for the
  // ruleset.
  base::Value::Dict GetManifestValue() const;
};

// Helper to build an extension manifest which uses the
// kDeclarativeNetRequestKey manifest key. `hosts` specifies the host
// permissions to grant. `flags` is a bitmask of ConfigFlag to configure the
// extension. `ruleset_info` specifies the static rulesets for the extension.
base::Value::Dict CreateManifest(
    const std::vector<TestRulesetInfo>& ruleset_info,
    const std::vector<std::string>& hosts = {},
    unsigned flags = ConfigFlag::kConfig_None,
    const std::string& extension_name = "Test Extension");

// Returns a base::Value::List corresponding to a vector of strings.
base::Value::List ToListValue(const std::vector<std::string>& vec);

// Returns a base::Value::List corresponding to a vector of TestRules.
base::Value::List ToListValue(const std::vector<TestRule>& rules);

// Writes the rulesets specified in `ruleset_info` in the given `extension_dir`
// together with the manifest file. `hosts` specifies the host permissions, the
// extensions should have. `flags` is a bitmask of ConfigFlag to configure the
// extension.
void WriteManifestAndRulesets(
    const base::FilePath& extension_dir,
    const std::vector<TestRulesetInfo>& ruleset_info,
    const std::vector<std::string>& hosts,
    unsigned flags = ConfigFlag::kConfig_None,
    const std::string& extension_name = "Test Extension");

// Specialization of WriteManifestAndRulesets above for an extension with a
// single static ruleset.
void WriteManifestAndRuleset(
    const base::FilePath& extension_dir,
    const TestRulesetInfo& ruleset_info,
    const std::vector<std::string>& hosts,
    unsigned flags = ConfigFlag::kConfig_None,
    const std::string& extension_name = "Test Extension");

}  // namespace extensions::declarative_net_request

#endif  // EXTENSIONS_COMMON_API_DECLARATIVE_NET_REQUEST_TEST_UTILS_H_