blob: 0c2f435cb511e50c3303c7aaba3767489d217b71 [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 "components/url_pattern_index/url_rule_util.h"
#include "base/macros.h"
#include "base/strings/string_util.h"
#include "components/url_pattern_index/flat/url_pattern_index_generated.h"
namespace url_pattern_index {
namespace {
std::string AnchorToString(url_pattern_index::flat::AnchorType anchor_type) {
switch (anchor_type) {
case url_pattern_index::flat::AnchorType_NONE:
return std::string();
case url_pattern_index::flat::AnchorType_SUBDOMAIN:
return "||";
case url_pattern_index::flat::AnchorType_BOUNDARY:
return "|";
}
NOTREACHED();
return std::string();
}
// Class that aids in appending options to a pretty-printed rule.
class OptionsPrinter {
public:
OptionsPrinter() = default;
// If this is the first printed option for the rule, add a $ separator,
// otherwise a comma.
std::string PrintOption(const std::string& option) {
std::string out = printed_options_ ? "," : "$";
printed_options_ = true;
return out + option;
}
private:
bool printed_options_ = false;
DISALLOW_COPY_AND_ASSIGN(OptionsPrinter);
};
std::string PartyOptionsToString(
OptionsPrinter* options_printer,
const url_pattern_index::flat::UrlRule* flat_rule) {
std::string out;
bool third_party = flat_rule->options() &
url_pattern_index::flat::OptionFlag_APPLIES_TO_THIRD_PARTY;
bool first_party = flat_rule->options() &
url_pattern_index::flat::OptionFlag_APPLIES_TO_FIRST_PARTY;
if (first_party ^ third_party) {
if (first_party)
out += options_printer->PrintOption("~third-party");
else
out += options_printer->PrintOption("third-party");
}
return out;
}
std::string TypeOptionsToString(
OptionsPrinter* options_printer,
const url_pattern_index::flat::UrlRule* flat_rule) {
std::string out;
if (flat_rule->activation_types() &
url_pattern_index::flat::ActivationType_DOCUMENT) {
out += options_printer->PrintOption("document");
}
if (flat_rule->activation_types() &
url_pattern_index::flat::ActivationType_GENERIC_BLOCK) {
out += options_printer->PrintOption("genericblock");
}
// Filterlists do not support the "main_frame" and "csp_report" element types.
// Hence we ignore them here.
constexpr uint16_t kSupportedElementTypes =
url_pattern_index::flat::ElementType_ANY &
~url_pattern_index::flat::ElementType_MAIN_FRAME &
~url_pattern_index::flat::ElementType_CSP_REPORT;
uint16_t types = flat_rule->element_types() & kSupportedElementTypes;
if (types == kSupportedElementTypes)
return out;
if (types & url_pattern_index::flat::ElementType_OTHER)
out += options_printer->PrintOption("other");
if (types & url_pattern_index::flat::ElementType_SCRIPT)
out += options_printer->PrintOption("script");
if (types & url_pattern_index::flat::ElementType_IMAGE)
out += options_printer->PrintOption("image");
if (types & url_pattern_index::flat::ElementType_STYLESHEET)
out += options_printer->PrintOption("stylesheet");
if (types & url_pattern_index::flat::ElementType_OBJECT)
out += options_printer->PrintOption("object");
if (types & url_pattern_index::flat::ElementType_XMLHTTPREQUEST)
out += options_printer->PrintOption("xmlhttprequest");
if (types & url_pattern_index::flat::ElementType_OBJECT_SUBREQUEST)
out += options_printer->PrintOption("object-subrequest");
if (types & url_pattern_index::flat::ElementType_SUBDOCUMENT)
out += options_printer->PrintOption("subdocument");
if (types & url_pattern_index::flat::ElementType_PING)
out += options_printer->PrintOption("ping");
if (types & url_pattern_index::flat::ElementType_MEDIA)
out += options_printer->PrintOption("media");
if (types & url_pattern_index::flat::ElementType_FONT)
out += options_printer->PrintOption("font");
if (types & url_pattern_index::flat::ElementType_WEBSOCKET)
out += options_printer->PrintOption("websocket");
return out;
}
std::string ConvertFlatString(const flatbuffers::String* string) {
return string ? std::string(string->data(), string->size()) : "";
}
std::string DomainOptionsToString(
OptionsPrinter* options_printer,
const url_pattern_index::flat::UrlRule* flat_rule) {
std::string out;
if (!flat_rule->domains_included() && !flat_rule->domains_excluded())
return "";
out += options_printer->PrintOption("domain=");
bool first = true;
if (flat_rule->domains_included()) {
for (auto* domain : *flat_rule->domains_included()) {
if (!first)
out += "|";
first = false;
out += ConvertFlatString(domain);
}
}
if (flat_rule->domains_excluded()) {
for (auto* domain : *flat_rule->domains_excluded()) {
if (!first)
out += "|";
first = false;
out += "~" + ConvertFlatString(domain);
}
}
return out;
}
} // namespace
std::string FlatUrlRuleToFilterlistString(const flat::UrlRule* flat_rule) {
std::string out;
if (flat_rule->options() & url_pattern_index::flat::OptionFlag_IS_WHITELIST)
out += "@@";
out += AnchorToString(flat_rule->anchor_left());
std::string pattern = ConvertFlatString(flat_rule->url_pattern());
// Add a wildcard to pattern if necessary to differentiate it from a regex.
// E.g., /foo/ should be /foo/*.
if (flat_rule->url_pattern_type() !=
url_pattern_index::flat::UrlPatternType_REGEXP &&
pattern.size() >= 2 && pattern[0] == '/' &&
pattern[pattern.size() - 1] == '/') {
pattern += "*";
}
out += pattern;
out += AnchorToString(flat_rule->anchor_right());
OptionsPrinter options_printer;
out += PartyOptionsToString(&options_printer, flat_rule);
// TODO(csharrison): Consider printing something for case-insensitive /
// case-sensitive rules.
out += TypeOptionsToString(&options_printer, flat_rule);
out += DomainOptionsToString(&options_printer, flat_rule);
return out;
}
} // namespace url_pattern_index