Commit 94338e59 authored by Josh Karlin's avatar Josh Karlin Committed by Commit Bot

Pretty printing for flatbuffer url rules.

Bug: 793025

Change-Id: I9707ded8397c178ab3cdd65c2c71851c64b00c00
Reviewed-on: https://chromium-review.googlesource.com/889791
Commit-Queue: Josh Karlin <jkarlin@chromium.org>
Reviewed-by: default avatarCharlie Harrison <csharrison@chromium.org>
Cr-Commit-Position: refs/heads/master@{#532592}
parent d59d15f8
...@@ -48,6 +48,17 @@ static_library("test_support") { ...@@ -48,6 +48,17 @@ static_library("test_support") {
] ]
} }
static_library("util") {
sources = [
"url_rule_util.cc",
"url_rule_util.h",
]
deps = [
":url_pattern_index",
"//base",
]
}
source_set("unit_tests") { source_set("unit_tests") {
testonly = true testonly = true
sources = [ sources = [
...@@ -58,10 +69,12 @@ source_set("unit_tests") { ...@@ -58,10 +69,12 @@ source_set("unit_tests") {
"unindexed_ruleset_unittest.cc", "unindexed_ruleset_unittest.cc",
"url_pattern_index_unittest.cc", "url_pattern_index_unittest.cc",
"url_pattern_unittest.cc", "url_pattern_unittest.cc",
"url_rule_util_unittest.cc",
] ]
deps = [ deps = [
":test_support", ":test_support",
":url_pattern_index", ":url_pattern_index",
":util",
"//base", "//base",
"//testing/gtest", "//testing/gtest",
"//third_party/protobuf:protobuf_lite", "//third_party/protobuf:protobuf_lite",
......
// 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");
}
uint16_t types = flat_rule->element_types();
if (types == url_pattern_index::flat::ElementType_ANY)
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 FlatUrlRuleToString(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);
if (flat_rule->options() & url_pattern_index::flat::OptionFlag_IS_MATCH_CASE)
out += options_printer.PrintOption("match-case");
out += TypeOptionsToString(&options_printer, flat_rule);
out += DomainOptionsToString(&options_printer, flat_rule);
return out;
}
} // namespace url_pattern_index
// 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.
#ifndef COMPONENTS_URL_PATTERN_INDEX_URL_RULE_UTIL_H_
#define COMPONENTS_URL_PATTERN_INDEX_URL_RULE_UTIL_H_
#include <string>
namespace url_pattern_index {
namespace flat {
struct UrlRule;
}
// Prints a UrlRule in string form.
std::string FlatUrlRuleToString(const flat::UrlRule* flat_rule);
} // namespace url_pattern_index
#endif // COMPONENTS_URL_PATTERN_INDEX_URL_RULE_UTIL_H_
// 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 <cmath>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "components/url_pattern_index/url_pattern.h"
#include "components/url_pattern_index/url_pattern_index.h"
#include "components/url_pattern_index/url_rule_test_support.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace url_pattern_index {
namespace {
proto::UrlRule MakeProtoRule(proto::RuleSemantics semantics,
const UrlPattern& url_pattern,
proto::SourceType source_type,
proto::ElementType types,
const std::vector<std::string>& domains) {
proto::UrlRule rule;
rule.set_semantics(semantics);
rule.set_source_type(source_type);
rule.set_element_types(types);
rule.set_url_pattern_type(url_pattern.type());
rule.set_anchor_left(url_pattern.anchor_left());
rule.set_anchor_right(url_pattern.anchor_right());
rule.set_match_case(url_pattern.match_case());
rule.set_url_pattern(url_pattern.url_pattern().as_string());
testing::AddDomains(domains, &rule);
return rule;
}
struct RuleTest {
const char* rule_string;
const char* match_string;
};
class UrlRuleUtilTest : public ::testing::Test {
protected:
UrlRuleUtilTest() = default;
const flat::UrlRule* MakeFlatRule(const proto::UrlRule& rule) {
auto offset = url_pattern_index::SerializeUrlRule(rule, &flat_builder_);
return flatbuffers::GetTemporaryPointer(flat_builder_, offset);
}
flatbuffers::FlatBufferBuilder flat_builder_;
private:
DISALLOW_COPY_AND_ASSIGN(UrlRuleUtilTest);
};
TEST_F(UrlRuleUtilTest, Blacklist) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, Whitelist) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("@@example.com/", FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, LeftAnchor) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("|example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("|example.com/", FlatUrlRuleToString(flat_rule));
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("||example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("||example.com/", FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, RightAnchor) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com", FlatUrlRuleToString(flat_rule));
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("|example.com|"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("|example.com|", FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, NonRegex) {
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("/foo/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("/foo/*", FlatUrlRuleToString(flat_rule));
// Show that whitelist rules work too.
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_WHITELIST, UrlPattern("/foo/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("@@/foo/*", FlatUrlRuleToString(flat_rule));
// TODO(jkarlin): If regex support is added to UrlRule, verify that regex
// rules don't get the '*' appended.
}
TEST_F(UrlRuleUtilTest, Party) {
const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("||example.com/"),
proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("||example.com/$third-party", FlatUrlRuleToString(flat_rule));
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("||example.com/"),
proto::SOURCE_TYPE_FIRST_PARTY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("||example.com/$~third-party", FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, MultipleOptions) {
const flat::UrlRule* flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("||example.com/"),
proto::SOURCE_TYPE_THIRD_PARTY, proto::ELEMENT_TYPE_SCRIPT, {}));
EXPECT_EQ("||example.com/$third-party,script",
FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, ElementType) {
// Test a single type.
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_SCRIPT, {}));
EXPECT_EQ("example.com/$script", FlatUrlRuleToString(flat_rule));
// Test blocking every type.
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
// Block everything except other. This test will need to be updated as
// proto::ElementType is changed.
flat_rule = MakeFlatRule(MakeProtoRule(
proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY,
static_cast<proto::ElementType>(proto::ELEMENT_TYPE_ALL - 1), {}));
std::string expected =
"example.com/"
"$script,image,stylesheet,object,xmlhttprequest,object-subrequest,"
"subdocument,ping,media,font,websocket";
EXPECT_EQ(expected, FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, ActivationType) {
// Test with no activiation type.
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
// Test with a document activation type.
auto proto_rule =
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {});
proto_rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT);
flat_rule = MakeFlatRule(proto_rule);
EXPECT_EQ("example.com/$document", FlatUrlRuleToString(flat_rule));
// Test with Document & Generic block types.
proto_rule.set_activation_types(proto::ACTIVATION_TYPE_DOCUMENT |
proto::ACTIVATION_TYPE_GENERICBLOCK);
flat_rule = MakeFlatRule(proto_rule);
EXPECT_EQ("example.com/$document,genericblock",
FlatUrlRuleToString(flat_rule));
}
TEST_F(UrlRuleUtilTest, DomainList) {
// Test with no domains set.
const flat::UrlRule* flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL, {}));
EXPECT_EQ("example.com/", FlatUrlRuleToString(flat_rule));
// Test with domains set.
flat_rule = MakeFlatRule(
MakeProtoRule(proto::RULE_SEMANTICS_BLACKLIST, UrlPattern("example.com/"),
proto::SOURCE_TYPE_ANY, proto::ELEMENT_TYPE_ALL,
{"foo.example.com", "~bar.example.com"}));
EXPECT_EQ("example.com/$domain=foo.example.com|~bar.example.com",
FlatUrlRuleToString(flat_rule));
}
} // namespace
} // namespace url_pattern_index
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