aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libserver/css/css_parser.cxx65
-rw-r--r--src/libserver/css/css_parser.hxx10
-rw-r--r--src/libserver/css/css_property.hxx2
-rw-r--r--src/libserver/css/css_rule.cxx49
-rw-r--r--src/libserver/css/css_rule.hxx5
5 files changed, 119 insertions, 12 deletions
diff --git a/src/libserver/css/css_parser.cxx b/src/libserver/css/css_parser.cxx
index 8d37a26a8..49b42021c 100644
--- a/src/libserver/css/css_parser.cxx
+++ b/src/libserver/css/css_parser.cxx
@@ -159,7 +159,14 @@ public:
explicit css_parser(css_style_sheet *existing, rspamd_mempool_t *pool) :
style_object(existing), pool(pool) {}
+ /*
+ * Process input css blocks
+ */
std::unique_ptr<css_consumed_block> consume_css_blocks(const std::string_view &sv);
+ /*
+ * Process a single css rule
+ */
+ std::unique_ptr<css_consumed_block> consume_css_rule(const std::string_view &sv);
bool consume_input(const std::string_view &sv);
auto get_object_maybe(void) -> tl::expected<std::unique_ptr<css_style_sheet>, css_parse_error> {
@@ -569,6 +576,38 @@ css_parser::consume_css_blocks(const std::string_view &sv) -> std::unique_ptr<cs
return consumed_blocks;
}
+auto
+css_parser::consume_css_rule(const std::string_view &sv) -> std::unique_ptr<css_consumed_block>
+{
+ tokeniser = std::make_unique<css_tokeniser>(pool, sv);
+ auto ret = true;
+
+ auto rule_block =
+ std::make_unique<css_consumed_block>(css_consumed_block::parser_tag_type::css_simple_block);
+
+ while (!eof && ret) {
+ auto next_token = tokeniser->next_token();
+
+ switch (next_token.type) {
+ case css_parser_token::token_type::eof_token:
+ eof = true;
+ break;
+ case css_parser_token::token_type::whitespace_token:
+ /* Ignore whitespaces */
+ break;
+ default:
+ tokeniser->pushback_token(std::move(next_token));
+ ret = component_value_consumer(rule_block);
+ break;
+ }
+
+ }
+
+ tokeniser.reset(nullptr); /* No longer needed */
+
+ return rule_block;
+}
+
bool css_parser::consume_input(const std::string_view &sv)
{
auto &&consumed_blocks = consume_css_blocks(sv);
@@ -702,6 +741,32 @@ get_selectors_parser_functor(rspamd_mempool_t *pool,
};
}
+auto
+get_rules_parser_functor(rspamd_mempool_t *pool,
+ const std::string_view &st) -> blocks_gen_functor
+{
+ css_parser parser(pool);
+
+ auto &&consumed_blocks = parser.consume_css_rule(st);
+ const auto &rules = consumed_blocks->get_blocks_or_empty();
+
+ auto cur = rules.begin();
+ auto last = rules.end();
+
+ return [cur, consumed_blocks = std::move(consumed_blocks), last](void) mutable
+ -> const css_consumed_block & {
+ if (cur != last) {
+ const auto &ret = (*cur);
+
+ ++cur;
+
+ return *ret;
+ }
+
+ return css_parser_eof_block;
+ };
+}
+
/*
* Wrapper for the parser
diff --git a/src/libserver/css/css_parser.hxx b/src/libserver/css/css_parser.hxx
index af79abb68..ec6d5159a 100644
--- a/src/libserver/css/css_parser.hxx
+++ b/src/libserver/css/css_parser.hxx
@@ -192,9 +192,19 @@ auto parse_css(rspamd_mempool_t *pool, const std::string_view &st,
css_style_sheet *other)
-> tl::expected<std::unique_ptr<css_style_sheet>, css_parse_error>;
+/*
+ * Creates a functor to consume css selectors sequence
+ */
auto get_selectors_parser_functor(rspamd_mempool_t *pool,
const std::string_view &st) -> blocks_gen_functor;
+/*
+ * Creates a functor to process a rule definition (e.g. from embedded style tag for
+ * an element)
+ */
+auto get_rules_parser_functor(rspamd_mempool_t *pool,
+ const std::string_view &st) -> blocks_gen_functor;
+
}
#endif //RSPAMD_CSS_PARSER_HXX
diff --git a/src/libserver/css/css_property.hxx b/src/libserver/css/css_property.hxx
index 973000b39..82ef9808c 100644
--- a/src/libserver/css/css_property.hxx
+++ b/src/libserver/css/css_property.hxx
@@ -54,6 +54,8 @@ struct alignas(int) css_property {
css_property_type type;
css_property_flag flag;
+ css_property(css_property_type t, css_property_flag fl = css_property_flag::FLAG_NORMAL) :
+ type(t), flag(fl) {}
static tl::expected<css_property,css_parse_error> from_token(
const css_parser_token &tok);
diff --git a/src/libserver/css/css_rule.cxx b/src/libserver/css/css_rule.cxx
index c301ebdca..3afe522e6 100644
--- a/src/libserver/css/css_rule.cxx
+++ b/src/libserver/css/css_rule.cxx
@@ -18,6 +18,9 @@
#include "css.hxx"
#include <limits>
+#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
+#include "doctest/doctest.h"
+
namespace rspamd::css {
/* Class methods */
@@ -111,8 +114,7 @@ namespace rspamd::css {
static auto
allowed_property_value(const css_property &prop, const css_consumed_block &parser_block)
- -> std::optional<css_value>
-{
+-> std::optional<css_value> {
if (prop.is_color()) {
if (parser_block.is_token()) {
/* A single token */
@@ -170,8 +172,7 @@ allowed_property_value(const css_property &prop, const css_consumed_block &parse
auto process_declaration_tokens(rspamd_mempool_t *pool,
blocks_gen_functor &&next_block_functor)
- -> css_declarations_block_ptr
-{
+-> css_declarations_block_ptr {
css_declarations_block_ptr ret;
bool can_continue = true;
css_property cur_property{css_property_type::PROPERTY_NYI,
@@ -315,8 +316,7 @@ auto process_declaration_tokens(rspamd_mempool_t *pool,
auto
css_declarations_block::merge_block(const css_declarations_block &other, merge_type how)
- -> void
-{
+-> void {
const auto &other_rules = other.get_rules();
for (const auto &rule : other_rules) {
@@ -324,7 +324,7 @@ css_declarations_block::merge_block(const css_declarations_block &other, merge_t
if (found_it != rules.end()) {
/* Duplicate, need to merge */
- switch(how) {
+ switch (how) {
case merge_type::merge_override:
/* Override */
rules.insert(rule);
@@ -345,9 +345,38 @@ css_declarations_block::merge_block(const css_declarations_block &other, merge_t
}
}
-void css_rule::add_value(const css_value &value)
-{
+void css_rule::add_value(const css_value &value) {
values.push_back(value);
}
-} \ No newline at end of file
+TEST_SUITE("css rules") {
+ TEST_CASE("simple css rules") {
+ const std::vector<std::pair<const char *, std::vector<css_property>>> cases{
+ {
+ "font-size:12.0pt;line-height:115%",
+ {css_property(css_property_type::PROPERTY_FONT_SIZE)}
+ },
+ {
+ "font-size:12.0pt;display:none",
+ {css_property(css_property_type::PROPERTY_FONT_SIZE),
+ css_property(css_property_type::PROPERTY_DISPLAY)}
+ }
+ };
+
+ auto *pool = rspamd_mempool_new(rspamd_mempool_suggest_size(),
+ "css", 0);
+
+ for (const auto &c : cases) {
+ auto res = process_declaration_tokens(pool,
+ get_rules_parser_functor(pool, c.first));
+
+ CHECK(res.get() != nullptr);
+
+ for (auto i = 0; i < c.second.size(); i ++) {
+ CHECK(res->has_property(c.second[i]));
+ }
+ }
+ }
+}
+
+} // namespace rspamd::css \ No newline at end of file
diff --git a/src/libserver/css/css_rule.hxx b/src/libserver/css/css_rule.hxx
index ec9ccde42..adf01437f 100644
--- a/src/libserver/css/css_rule.hxx
+++ b/src/libserver/css/css_rule.hxx
@@ -76,6 +76,7 @@ public:
namespace rspamd::css {
+
class css_declarations_block {
public:
using rule_shared_ptr = std::shared_ptr<css_rule>;
@@ -95,8 +96,8 @@ public:
return rules;
}
- auto has_rule(const css_rule &rule) const -> bool {
- return (rules.find(rule) != rules.end());
+ auto has_property(const css_property &prop) const -> bool {
+ return (rules.find(css_rule{prop}) != rules.end());
}
private:
robin_hood::unordered_flat_set<rule_shared_ptr, rule_shared_hash, rule_shared_eq> rules;