* limitations under the License.
*/
-#include "css.h"
#include "css.hxx"
#include "contrib/robin-hood/robin_hood.h"
#include "css_parser.hxx"
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest/doctest.h"
-static void
-rspamd_css_dtor(void *p)
-{
- rspamd::css::css_style_sheet *style =
- reinterpret_cast<rspamd::css::css_style_sheet *>(p);
-
- delete style;
-}
-
-rspamd_css_ptr
-rspamd_css_parse_style(rspamd_mempool_t *pool, const gchar *begin, gsize len,
- rspamd_css_ptr existing_style,
- GError **err)
-{
- 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_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 {
- g_set_error(err, g_quark_from_static_string("css"),
- static_cast<int>(parse_res.error().type),
- "parse error");
- return nullptr;
- }
-}
-
namespace rspamd::css {
INIT_LOG_MODULE_PUBLIC(css);
}
}
+auto
+css_parse_style(rspamd_mempool_t *pool,
+ std::string_view input,
+ std::shared_ptr<css_style_sheet> &&existing)
+ -> css_return_pair
+{
+ auto parse_res = rspamd::css::parse_css(pool, input,
+ std::forward<std::shared_ptr<css_style_sheet>>(existing));
+
+ if (parse_res.has_value()) {
+ return std::make_pair(parse_res.value(), css_parse_error());
+ }
+
+ return std::make_pair(nullptr, parse_res.error());
+}
+
}
\ No newline at end of file
+++ /dev/null
-/*-
- * Copyright 2021 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef RSPAMD_CSS_H
-#define RSPAMD_CSS_H
-
-#include "config.h"
-#include "mem_pool.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-typedef void * rspamd_css_ptr;
-
-rspamd_css_ptr rspamd_css_parse_style (rspamd_mempool_t *pool,
- const gchar *begin,
- gsize len,
- rspamd_css_ptr existing_style,
- GError **err);
-
-/*
- * Unescape css
- */
-const gchar *rspamd_css_unescape (rspamd_mempool_t *pool,
- const guchar *begin,
- gsize len,
- gsize *outlen);
-#ifdef __cplusplus
-}
-#endif
-
-#endif //RSPAMD_CSS_H
#include <string>
#include <memory>
#include "logger.h"
-#include "css.h"
#include "css_rule.hxx"
#include "css_selector.hxx"
std::unique_ptr<impl> pimpl;
};
+using css_return_pair = std::pair<std::shared_ptr<css_style_sheet>, css_parse_error>;
+auto css_parse_style(rspamd_mempool_t *pool,
+ std::string_view input,
+ std::shared_ptr<css_style_sheet> &&existing) ->
+ css_return_pair;
+
}
#endif //RSPAMD_CSS_H
\ No newline at end of file
public:
css_parser(void) = delete; /* Require mempool to be set for logging */
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;
+ style_object.reset();
}
/*
* 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) :
+ explicit css_parser(std::shared_ptr<css_style_sheet> &&existing, rspamd_mempool_t *pool) :
style_object(existing), pool(pool) {}
/*
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> {
+ auto get_object_maybe(void) -> tl::expected<std::shared_ptr<css_style_sheet>, css_parse_error> {
if (style_object) {
- return std::move(style_object);
+ return style_object;
}
return tl::make_unexpected(error);
/* Helper parser methods */
static 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::shared_ptr<css_style_sheet> style_object;
std::unique_ptr<css_tokeniser> tokeniser;
css_parse_error error;
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;
}
if (!style_object) {
- style_object = std::make_unique<css_style_sheet>(pool);
+ style_object = std::make_shared<css_style_sheet>(pool);
}
for (auto &&rule : rules) {
* Wrapper for the parser
*/
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>
+ std::shared_ptr<css_style_sheet> &&other)
+ -> tl::expected<std::shared_ptr<css_style_sheet>, css_parse_error>
{
- css_parser parser(other, pool);
+ css_parser parser(std::forward<std::shared_ptr<css_style_sheet>>(other), pool);
std::string_view processed_input;
if (css_parser::need_unescape(st)) {
}
/* We now merge all styles together */
- css_style_sheet *merged = nullptr;
+ std::shared_ptr<css_style_sheet> merged;
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();
+ auto ret = parse_css(pool, c, std::move(merged));
+ merged.swap(ret.value());
}
- CHECK(merged != nullptr);
+ CHECK(merged.get() != nullptr);
rspamd_mempool_delete(pool);
}
* 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>;
+ std::shared_ptr<css_style_sheet> &&other)
+ -> tl::expected<std::shared_ptr<css_style_sheet>, css_parse_error>;
/*
* Creates a functor to consume css selectors sequence
PARSE_ERROR_BAD_NESTING,
PARSE_ERROR_NYI,
PARSE_ERROR_UNKNOWN_ERROR,
+ PARSE_ERROR_NO_ERROR,
};
struct css_parse_error {
explicit css_parse_error (css_parse_error_type type, const std::string &description) :
type(type), description(description) {}
- explicit css_parse_error (css_parse_error_type type) :
+ explicit css_parse_error (css_parse_error_type type = css_parse_error_type::PARSE_ERROR_NO_ERROR) :
type(type) {}
- css_parse_error() = default;
};
}
#include "html_block.hxx"
#include "html.hxx"
#include "libserver/css/css_value.hxx"
+#include "libserver/css/css.hxx"
#include "url.h"
#include "contrib/libucl/khash.h"
#include "libmime/images.h"
-#include "css/css.h"
#include "libutil/cxx/utf8_util.h"
#include "html_tag_defs.hxx"
* We just search for the first </s substring and then pass
* the content to the parser (if needed)
*/
- goffset end_style = rspamd_substring_search (p, end - p,
+ auto end_style = rspamd_substring_search (p, end - p,
"</", 2);
if (end_style == -1 || g_ascii_tolower (p[end_style + 2]) != 's') {
/* Invalid style */
else {
if (allow_css) {
- GError *err = nullptr;
- 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);
- g_error_free (err);
+ auto ret_maybe = rspamd::css::parse_css(pool, {p, std::size_t(end_style)},
+ std::move(hc->css_style));
+
+ if (!ret_maybe.has_value()) {
+ auto err_str = fmt::format("cannot parse css (error code: {}): {}",
+ static_cast<int>(ret_maybe.error().type),
+ ret_maybe.error().description.value_or("unknown error"));
+ msg_info_pool ("cannot parse css: %*s",
+ (int)err_str.size(), err_str.data());
}
+
+ hc->css_style = ret_maybe.value();
}
p += end_style;
#include <memory>
#include "function2/function2.hpp"
+namespace rspamd::css {
+/* Forward declaration */
+class css_style_sheet;
+}
+
namespace rspamd::html {
struct html_block;
std::vector<html_image *> images;
std::vector<std::unique_ptr<struct html_tag>> all_tags;
std::string parsed;
- void *css_style;
+ std::shared_ptr<css::css_style_sheet> css_style;
/* Preallocate and reserve all internal structures */
html_content() {