aboutsummaryrefslogtreecommitdiffstats
path: root/src/libserver
diff options
context:
space:
mode:
Diffstat (limited to 'src/libserver')
-rw-r--r--src/libserver/css/css.cxx17
-rw-r--r--src/libserver/css/css.h10
-rw-r--r--src/libserver/css/css_parser.cxx45
-rw-r--r--src/libserver/css/css_parser.hxx8
-rw-r--r--src/libserver/html.c3
-rw-r--r--src/libserver/html.h1
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;
};
/*