Browse Source

[Project] Css: Add rules processing functions and tests

tags/3.0
Vsevolod Stakhov 3 years ago
parent
commit
25661e2ab2

+ 65
- 0
src/libserver/css/css_parser.cxx View File

@@ -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

+ 10
- 0
src/libserver/css/css_parser.hxx View File

@@ -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

+ 2
- 0
src/libserver/css/css_property.hxx View File

@@ -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);


+ 39
- 10
src/libserver/css/css_rule.cxx View File

@@ -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);
}

}
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

+ 3
- 2
src/libserver/css/css_rule.hxx View File

@@ -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;

Loading…
Cancel
Save