summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2021-03-09 20:49:16 +0000
committerVsevolod Stakhov <vsevolod@highsecure.ru>2021-03-09 20:49:16 +0000
commit9531673b2c627d94bea3e136ea956eca6a7364a3 (patch)
tree89b07f48d08fec30373a7f40b7d6ba7b4a0ad6c6 /src
parent664b9385107575c25a14aecc777c1d360d020382 (diff)
downloadrspamd-9531673b2c627d94bea3e136ea956eca6a7364a3.tar.gz
rspamd-9531673b2c627d94bea3e136ea956eca6a7364a3.zip
[Project] Css: Rework css block structure
Diffstat (limited to 'src')
-rw-r--r--src/libserver/css/css_property.hxx2
-rw-r--r--src/libserver/css/css_rule.cxx97
-rw-r--r--src/libserver/css/css_rule.hxx94
-rw-r--r--src/libserver/css/css_value.hxx17
4 files changed, 176 insertions, 34 deletions
diff --git a/src/libserver/css/css_property.hxx b/src/libserver/css/css_property.hxx
index 597fc20c5..b72b655f9 100644
--- a/src/libserver/css/css_property.hxx
+++ b/src/libserver/css/css_property.hxx
@@ -118,6 +118,8 @@ struct alignas(int) css_property {
constexpr auto is_normal_number(void) const -> bool {
return type == css_property_type::PROPERTY_OPACITY;
}
+
+ auto operator==(const css_property &other) const { return type == other.type; }
};
diff --git a/src/libserver/css/css_rule.cxx b/src/libserver/css/css_rule.cxx
index a29577fe9..a706c759c 100644
--- a/src/libserver/css/css_rule.cxx
+++ b/src/libserver/css/css_rule.cxx
@@ -15,9 +15,87 @@
*/
#include "css_rule.hxx"
+#include <limits>
namespace rspamd::css {
+/* Class methods */
+void css_rule::override_values(const css_rule &other)
+{
+ values.resize(0);
+ values.reserve(other.values.size());
+
+ std::copy(other.values.begin(), other.values.end(),
+ std::back_inserter(values));
+}
+
+void css_rule::merge_values(const css_rule &other)
+{
+ int bits = 0;
+ /* Ensure that our bitset is large enough */
+ static_assert(static_cast<std::size_t>(css_value::css_value_type::CSS_VALUE_NYI) << 1 <
+ std::numeric_limits<int>::max());
+
+ for (const auto &v : values) {
+ bits |= static_cast<int>(v.type);
+ }
+
+ /* Copy only not set values */
+ std::copy_if(other.values.begin(), other.values.end(), std::back_inserter(values),
+ [&bits](const auto &elt) -> bool {
+ return !isset(&bits, static_cast<int>(elt.type));
+ });
+}
+
+auto css_declarations_block::add_rule(rule_shared_ptr &&rule) -> void
+{
+ auto it = rules.find(rule);
+ auto &&remote_prop = rule->get_prop();
+
+ if (it != rules.end()) {
+ auto &&local_rule = *it;
+ auto &&local_prop = local_rule->get_prop();
+
+ if (local_prop.flag == css_property_flag::FLAG_IMPORTANT) {
+ if (remote_prop.flag == css_property_flag::FLAG_IMPORTANT) {
+ local_rule->override_values(*rule);
+ }
+ else {
+ /* Ignore remote not important over local important */
+ local_rule->merge_values(*rule);
+ }
+ }
+ else if (local_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) {
+ if (remote_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) {
+ local_rule->override_values(*rule);
+ }
+ else {
+ /* Ignore local not important over important */
+ local_rule->merge_values(*rule);
+ }
+ }
+ else {
+ if (remote_prop.flag == css_property_flag::FLAG_IMPORTANT) {
+ /* Override with remote */
+ local_rule->override_values(*rule);
+ }
+ else if (remote_prop.flag == css_property_flag::FLAG_NOT_IMPORTANT) {
+ /* Ignore remote not important over local normal */
+ }
+ else {
+ /* Merge both */
+ local_rule->merge_values(*rule);
+ }
+ }
+ }
+}
+
+}
+
+namespace rspamd::css {
+
+/* Static functions */
+
static auto
allowed_property_value(const css_property &prop, const css_consumed_block &parser_block)
-> std::optional<css_value>
@@ -70,15 +148,15 @@ allowed_property_value(const css_property &prop, const css_consumed_block &parse
auto process_declaration_tokens(rspamd_mempool_t *pool,
const blocks_gen_functor &next_block_functor)
- -> declarations_vec
+ -> css_declarations_block
{
- declarations_vec ret;
+ css_declarations_block ret;
bool can_continue = true;
css_property cur_property{css_property_type::PROPERTY_NYI,
css_property_flag::FLAG_NORMAL};
static const css_property bad_property{css_property_type::PROPERTY_NYI,
css_property_flag::FLAG_NORMAL};
- std::unique_ptr<css_rule> cur_rule;
+ std::shared_ptr<css_rule> cur_rule;
enum {
parse_property,
@@ -121,7 +199,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool,
}
else {
state = parse_value;
- cur_rule = std::make_unique<css_rule>(cur_property);
+ cur_rule = std::make_shared<css_rule>(cur_property);
}
}
}
@@ -131,7 +209,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool,
const auto &parser_tok = next_tok.get_token_or_empty();
if (parser_tok.type == css_parser_token::token_type::semicolon_token) {
- ret.push_back(std::move(cur_rule));
+ ret.add_rule(std::move(cur_rule));
state = parse_property;
seen_not = false;
continue;
@@ -199,7 +277,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool,
break;
case css_consumed_block::parser_tag_type::css_eof_block:
if (state == parse_value) {
- ret.push_back(std::move(cur_rule));
+ ret.add_rule(std::move(cur_rule));
}
can_continue = false;
break;
@@ -212,14 +290,9 @@ auto process_declaration_tokens(rspamd_mempool_t *pool,
return ret; /* copy elision */
}
-void css_rule::add_value(std::unique_ptr<css_value> &&value)
-{
- values.emplace_back(std::forward<std::unique_ptr<css_value>>(value));
-}
-
void css_rule::add_value(const css_value &value)
{
- values.emplace_back(std::make_unique<css_value>(css_value{value}));
+ values.push_back(value);
}
} \ No newline at end of file
diff --git a/src/libserver/css/css_rule.hxx b/src/libserver/css/css_rule.hxx
index 41a6ef3be..dd6158538 100644
--- a/src/libserver/css/css_rule.hxx
+++ b/src/libserver/css/css_rule.hxx
@@ -21,6 +21,7 @@
#include "css_value.hxx"
#include "css_property.hxx"
#include "css_parser.hxx"
+#include "contrib/robin-hood/robin_hood.h"
#include <vector>
#include <memory>
@@ -28,29 +29,35 @@ namespace rspamd::css {
class css_rule {
css_property prop;
- using css_values_vec = std::vector<std::unique_ptr<css_value> >;
+ using css_values_vec = std::vector<css_value>;
css_values_vec values;
+
public:
/* We must create css rule explicitly from a property and values */
css_rule() = delete;
+
css_rule(const css_rule &other) = delete;
+
/* Constructors */
- css_rule(css_rule &&other) = default;
- explicit css_rule(css_property &&prop, css_values_vec &&values) :
- prop(prop), values(std::forward<css_values_vec>(values)) {}
- explicit css_rule(const css_property &prop) : prop(prop), values{} {}
+ css_rule(css_rule &&other) noexcept = default;
+
+ explicit css_rule(css_property &&prop, css_values_vec &&values) noexcept :
+ prop(prop), values(std::forward<css_values_vec>(values)) {}
+
+ explicit css_rule(const css_property &prop) noexcept : prop(prop), values{} {}
+
/* Methods */
- void add_value(std::unique_ptr<css_value> &&value);
- void add_value(const css_value &value);
- constexpr const css_values_vec& get_values(void) const { return values; }
- constexpr const css_property& get_prop(void) const { return prop; }
-};
+ /* Comparison is special, as we care merely about property, not the values */
+ auto operator==(const css_rule &other) const { return prop == other.prop; }
-using declarations_vec = std::vector<std::unique_ptr<css_rule>>;
+ constexpr const css_values_vec &get_values(void) const { return values; }
+ constexpr const css_property &get_prop(void) const { return prop; }
-auto process_declaration_tokens(rspamd_mempool_t *pool,
- const blocks_gen_functor &next_token_functor)
- -> declarations_vec;
+ /* Import values from another rules according to the importance */
+ void override_values(const css_rule &other);
+ void merge_values(const css_rule &other);
+ void add_value(const css_value &value);
+};
}
@@ -59,10 +66,67 @@ namespace std {
template<>
class hash<rspamd::css::css_rule> {
public:
- constexpr size_t operator() (const rspamd::css::css_rule &rule) const {
+ constexpr auto operator()(const rspamd::css::css_rule &rule) const -> auto {
return hash<rspamd::css::css_property>()(rule.get_prop());
}
};
+
+}
+
+namespace rspamd::css {
+
+/*
+ * We have to define transparent hash and compare methods
+ *
+ * TODO: move to some utility library
+ */
+template<typename T>
+struct shared_ptr_equal {
+ using is_transparent = void; /* We want to find values in a set of shared_ptr by reference */
+ auto operator()(const std::shared_ptr<T> &a, const std::shared_ptr<T> &b) const {
+ return (*a) == (*b);
+ }
+ auto operator()(const std::shared_ptr<T> &a, const T &b) const {
+ return (*a) == b;
+ }
+ auto operator()(const T &a, const std::shared_ptr<T> &b) const {
+ return a == (*b);
+ }
+};
+
+template<typename T>
+struct shared_ptr_hash {
+ using is_transparent = void; /* We want to find values in a set of shared_ptr by reference */
+ auto operator()(const std::shared_ptr<T> &a) const {
+ return std::hash<T>()(*a);
+ }
+ auto operator()(const T &a) const {
+ return std::hash<T>()(a);
+ }
+};
+
+class css_declarations_block {
+public:
+ using rule_shared_ptr = std::shared_ptr<css_rule>;
+ using rule_shared_hash = shared_ptr_hash<css_rule>;
+ using rule_shared_eq = shared_ptr_equal<css_rule>;
+ css_declarations_block() = default;
+ auto add_rule(rule_shared_ptr &&rule) -> void;
+ auto get_rules(void) const -> const auto & {
+ return rules;
+ }
+
+ auto has_rule(const css_rule &rule) const -> bool {
+ return (rules.find(rule) != rules.end());
+ }
+private:
+ robin_hood::unordered_flat_set<rule_shared_ptr, rule_shared_hash, rule_shared_eq> rules;
+};
+
+auto process_declaration_tokens(rspamd_mempool_t *pool,
+ const blocks_gen_functor &next_token_functor)
+ -> css_declarations_block;
+
}
#endif //RSPAMD_CSS_RULE_HXX \ No newline at end of file
diff --git a/src/libserver/css/css_value.hxx b/src/libserver/css/css_value.hxx
index 64109c5f0..d7c8f5c45 100644
--- a/src/libserver/css/css_value.hxx
+++ b/src/libserver/css/css_value.hxx
@@ -59,20 +59,23 @@ enum class css_display_value {
* for simplicity
*/
struct css_value {
+ /* Bitset of known types */
enum class css_value_type {
- CSS_VALUE_COLOR,
- CSS_VALUE_NUMBER,
- CSS_VALUE_DISPLAY,
- CSS_VALUE_DIMENSION,
- CSS_VALUE_NYI,
- } type;
-
+ CSS_VALUE_COLOR = 1 << 0,
+ CSS_VALUE_NUMBER = 1 << 1,
+ CSS_VALUE_DISPLAY = 1 << 2,
+ CSS_VALUE_DIMENSION = 1 << 3,
+ CSS_VALUE_NYI = 1 << 4,
+ };
+
+ css_value_type type;
std::variant<css_color,
double,
css_display_value,
css_dimension,
std::monostate> value;
+ css_value() : type(css_value_type::CSS_VALUE_NYI) {}
css_value(const css_color &color) :
type(css_value_type::CSS_VALUE_COLOR), value(color) {}
css_value(double num) :