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 {
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);
/* 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;
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;
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) {
/*
/*
* 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)) {
}
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") {
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);
}
}
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;