diff options
Diffstat (limited to 'src/libserver')
-rw-r--r-- | src/libserver/css/css.cxx | 17 | ||||
-rw-r--r-- | src/libserver/css/css.h | 10 | ||||
-rw-r--r-- | src/libserver/css/css_parser.cxx | 45 | ||||
-rw-r--r-- | src/libserver/css/css_parser.hxx | 8 | ||||
-rw-r--r-- | src/libserver/html.c | 3 | ||||
-rw-r--r-- | src/libserver/html.h | 1 |
6 files changed, 65 insertions, 19 deletions
diff --git a/src/libserver/css/css.cxx b/src/libserver/css/css.cxx index 17ec165fc..033ecdc22 100644 --- a/src/libserver/css/css.cxx +++ b/src/libserver/css/css.cxx @@ -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 { diff --git a/src/libserver/css/css.h b/src/libserver/css/css.h index 78f24a549..1dabf00b8 100644 --- a/src/libserver/css/css.h +++ b/src/libserver/css/css.h @@ -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 diff --git a/src/libserver/css/css_parser.cxx b/src/libserver/css/css_parser.cxx index 104792693..8d37a26a8 100644 --- a/src/libserver/css/css_parser.cxx +++ b/src/libserver/css/css_parser.cxx @@ -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); } } diff --git a/src/libserver/css/css_parser.hxx b/src/libserver/css/css_parser.hxx index 4b5598fa9..af79abb68 100644 --- a/src/libserver/css/css_parser.hxx +++ b/src/libserver/css/css_parser.hxx @@ -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; diff --git a/src/libserver/html.c b/src/libserver/html.c index b56f3ef32..8dc8a8dac 100644 --- a/src/libserver/html.c +++ b/src/libserver/html.c @@ -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); diff --git a/src/libserver/html.h b/src/libserver/html.h index f8a5e18e4..83a2a7ee7 100644 --- a/src/libserver/html.h +++ b/src/libserver/html.h @@ -132,6 +132,7 @@ struct html_content { GPtrArray *images; GPtrArray *blocks; GByteArray *parsed; + void *css_style; }; /* |