Browse Source

[Project] Css: Implement styles merging

tags/3.0
Vsevolod Stakhov 3 years ago
parent
commit
162b69d568

+ 12
- 5
src/libserver/css/css.cxx View File

@@ -32,19 +32,26 @@ rspamd_css_dtor(void *p)
delete style;
}

rspamd_css
rspamd_css_ptr
rspamd_css_parse_style(rspamd_mempool_t *pool, const guchar *begin, gsize len,
GError **err)
rspamd_css_ptr existing_style,
GError **err)
{
auto parse_res = rspamd::css::parse_css(pool, {(const char* )begin, len});
auto parse_res = rspamd::css::parse_css(pool, {(const char* )begin, len},
reinterpret_cast<rspamd::css::css_style_sheet*>(existing_style));

if (parse_res.has_value()) {
/*
* Detach style pointer from the unique_ptr as it will be managed by
* C memory pool
*/
auto *detached_style = reinterpret_cast<rspamd_css>(parse_res.value().release());
rspamd_mempool_add_destructor(pool, rspamd_css_dtor, (void *)detached_style);
auto *detached_style = reinterpret_cast<rspamd_css_ptr>(parse_res.value().release());

/* We attach dtor merely if the existing style is not null */
if (!existing_style) {
rspamd_mempool_add_destructor(pool, rspamd_css_dtor, (void *) detached_style);
}

return detached_style;
}
else {

+ 6
- 4
src/libserver/css/css.h View File

@@ -23,11 +23,13 @@
#ifdef __cplusplus
extern "C" {
#endif
typedef void * rspamd_css;
typedef void * rspamd_css_ptr;

rspamd_css rspamd_css_parse_style (rspamd_mempool_t *pool,
const guchar *begin,
gsize len, GError **err);
rspamd_css_ptr rspamd_css_parse_style (rspamd_mempool_t *pool,
const guchar *begin,
gsize len,
rspamd_css_ptr existing_style,
GError **err);

/*
* Unescape css

+ 38
- 7
src/libserver/css/css_parser.cxx View File

@@ -147,7 +147,17 @@ auto css_consumed_block::debug_str(void) -> std::string {
class css_parser {
public:
css_parser(void) = delete; /* Require mempool to be set for logging */
explicit css_parser(rspamd_mempool_t *pool) : pool (pool) {}
explicit css_parser(rspamd_mempool_t *pool) : pool (pool) {
/* Int this case we need to remove style in case of parser error */
owned_style = true;
}

/*
* This constructor captures existing via unique_ptr, but it does not
* destruct it on errors (we assume that it is owned somewhere else)
*/
explicit css_parser(css_style_sheet *existing, rspamd_mempool_t *pool) :
style_object(existing), pool(pool) {}

std::unique_ptr<css_consumed_block> consume_css_blocks(const std::string_view &sv);
bool consume_input(const std::string_view &sv);
@@ -163,6 +173,13 @@ public:
/* Helper parser methods */
bool need_unescape(const std::string_view &sv);

~css_parser() {
if (!owned_style && style_object) {
/* Avoid double free */
(void)style_object.release();
}
}

private:
std::unique_ptr<css_style_sheet> style_object;
std::unique_ptr<css_tokeniser> tokeniser;
@@ -173,6 +190,7 @@ private:
int rec_level = 0;
const int max_rec = 20;
bool eof = false;
bool owned_style = false;

/* Consumers */
auto component_value_consumer(std::unique_ptr<css_consumed_block> &top) -> bool;
@@ -560,7 +578,9 @@ bool css_parser::consume_input(const std::string_view &sv)
return false;
}

style_object = std::make_unique<css_style_sheet>(pool);
if (!style_object) {
style_object = std::make_unique<css_style_sheet>(pool);
}

for (auto &&rule : rules) {
/*
@@ -686,10 +706,11 @@ get_selectors_parser_functor(rspamd_mempool_t *pool,
/*
* Wrapper for the parser
*/
auto parse_css(rspamd_mempool_t *pool, const std::string_view &st) ->
tl::expected<std::unique_ptr<css_style_sheet>, css_parse_error>
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>
{
css_parser parser(pool);
css_parser parser(other, pool);
std::string_view processed_input;

if (parser.need_unescape(st)) {
@@ -712,7 +733,7 @@ auto parse_css(rspamd_mempool_t *pool, const std::string_view &st) ->
}

return tl::make_unexpected(css_parse_error{css_parse_error_type::PARSE_ERROR_INVALID_SYNTAX,
"cannot parse input"});
"cannot parse input"});
}

TEST_SUITE("css parser") {
@@ -752,9 +773,19 @@ TEST_SUITE("css parser") {
rspamd_mempool_t *pool = rspamd_mempool_new(rspamd_mempool_suggest_size(),
"css", 0);
for (const auto &c : cases) {
CHECK_UNARY(parse_css(pool, c));
CHECK(parse_css(pool, c, nullptr).value().get() != nullptr);
}

/* We now merge all styles together */
css_style_sheet *merged = nullptr;
for (const auto &c : cases) {
auto ret = parse_css(pool, c, merged);
/* Avoid destruction as we are using this to interoperate with C */
merged = ret->release();
}

CHECK(merged != nullptr);

rspamd_mempool_delete(pool);
}
}

+ 6
- 2
src/libserver/css/css_parser.hxx View File

@@ -185,8 +185,12 @@ extern const css_consumed_block css_parser_eof_block;
using blocks_gen_functor = fu2::unique_function<const css_consumed_block &(void)>;

class css_style_sheet;
auto parse_css(rspamd_mempool_t *pool, const std::string_view &st) ->
tl::expected<std::unique_ptr<css_style_sheet>, css_parse_error>;
/*
* Update the existing stylesheet with another stylesheet
*/
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>;

auto get_selectors_parser_functor(rspamd_mempool_t *pool,
const std::string_view &st) -> blocks_gen_functor;

+ 2
- 1
src/libserver/html.c View File

@@ -3137,7 +3137,8 @@ rspamd_html_process_part_full (rspamd_mempool_t *pool,

if (allow_css) {
GError *err = NULL;
(void)rspamd_css_parse_style (pool, p, end_style, &err);
hc->css_style = rspamd_css_parse_style (pool, p, end_style, hc->css_style,
&err);

if (err) {
msg_info_pool ("cannot parse css: %e", err);

+ 1
- 0
src/libserver/html.h View File

@@ -132,6 +132,7 @@ struct html_content {
GPtrArray *images;
GPtrArray *blocks;
GByteArray *parsed;
void *css_style;
};

/*

Loading…
Cancel
Save