case css_selector::selector_type::SELECTOR_ID:
target_hash = &pimpl->id_selectors;
break;
- case css_selector::selector_type::SELECTOR_ELEMENT:
+ case css_selector::selector_type::SELECTOR_TAG:
target_hash = &pimpl->tags_selector;
break;
}
}
else {
/* Lowercase inplace */
- auto *nspace = reinterpret_cast<char *>(rspamd_mempool_alloc(pool, st.length()));
- auto *p = nspace;
-
- for (const auto c : st) {
- *p++ = g_ascii_tolower(c);
- }
-
- processed_input = std::string_view{nspace, (std::size_t)(p - nspace)};
+ auto *nspace = rspamd_mempool_alloc_buffer(pool, st.size());
+ rspamd_str_copy_lc(st.data(), nspace, st.size());
+ processed_input = std::string_view{nspace, st.size()};
}
if (parser.consume_input(processed_input)) {
TEST_SUITE("css parser") {
TEST_CASE("parse colors") {
const std::vector<const char *> cases{
- "p { color: rgb(100%, 50%, 0%); opacity: -1; width: 1em; display: none; } /* very transparent solid orange */",
+ "P { CoLoR: rgb(100%, 50%, 0%); opacity: -1; width: 1em; display: none; } /* very transparent solid orange ัะตัั */",
"p { color: rgb(100%, 50%, 0%); opacity: 2; display: inline; } /* very transparent solid orange */",
"p { color: rgb(100%, 50%, 0%); opacity: 0.5; } /* very transparent solid orange */\n",
"p { color: rgb(100%, 50%, 0%); opacity: 1; width: 99%; } /* very transparent solid orange */\n",
#include "css_selector.hxx"
#include "css.hxx"
+#include "libserver/html/html.hxx"
#include "fmt/core.h"
#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL
#include "doctest/doctest.h"
}
break;
}
- case css_parser_token::token_type::ident_token:
- cur_selector = std::make_unique<css_selector>(
- css_selector::selector_type::SELECTOR_ELEMENT);
- cur_selector->value = parser_tok.get_string_or_default("");
+ case css_parser_token::token_type::ident_token: {
+ auto tag_id = html::html_tag_by_name(parser_tok.get_string_or_default(""));
+
+ if (tag_id) {
+ cur_selector = std::make_unique<css_selector>(tag_id.value());
+ }
state = selector_process_state::selector_ident_consumed;
break;
+ }
case css_parser_token::token_type::hash_token:
cur_selector = std::make_unique<css_selector>(
css_selector::selector_type::SELECTOR_ID);
}
}
else if (state == selector_process_state::selector_ident_consumed) {
- if (parser_tok.type == css_parser_token::token_type::comma_token) {
+ if (parser_tok.type == css_parser_token::token_type::comma_token && cur_selector) {
/* Got full selector, attach it to the vector and go further */
msg_debug_css("attached selector: %s", cur_selector->debug_str().c_str());
ret.push_back(std::move(cur_selector));
}
else {
/* Ignore state; ignore all till ',' token or eof token */
- if (parser_tok.type == css_parser_token::token_type::comma_token) {
+ if (parser_tok.type == css_parser_token::token_type::comma_token && cur_selector) {
/* Got full selector, attach it to the vector and go further */
ret.push_back(std::move(cur_selector));
state = selector_process_state::selector_parse_start;
TEST_SUITE("css selectors") {
TEST_CASE("simple css selectors") {
const std::vector<std::pair<const char *, std::vector<css_selector::selector_type>>> cases{
- {"em", {css_selector::selector_type::SELECTOR_ELEMENT}},
+ {"em", {css_selector::selector_type::SELECTOR_TAG}},
{"*", {css_selector::selector_type::SELECTOR_ALL}},
{".class", {css_selector::selector_type::SELECTOR_CLASS}},
{"#id", {css_selector::selector_type::SELECTOR_ID}},
- {"em,.class,#id", {css_selector::selector_type::SELECTOR_ELEMENT,
+ {"em,.class,#id", {css_selector::selector_type::SELECTOR_TAG,
css_selector::selector_type::SELECTOR_CLASS,
css_selector::selector_type::SELECTOR_ID}},
};
*/
struct css_selector {
enum class selector_type {
- SELECTOR_ELEMENT, /* e.g. tr, for this value we use tag_id_t */
+ SELECTOR_TAG, /* e.g. tr, for this value we use tag_id_t */
SELECTOR_CLASS, /* generic class, e.g. .class */
SELECTOR_ID, /* e.g. #id */
SELECTOR_ALL /* * selector */
std::vector<css_selector_dep> dependencies;
auto to_tag(void) const -> std::optional<tag_id_t> {
- if (type == selector_type::SELECTOR_ELEMENT) {
+ if (type == selector_type::SELECTOR_TAG) {
return std::get<tag_id_t>(value);
}
return std::nullopt;
}
auto to_string(void) const -> std::optional<const std::string_view> {
- if (type != selector_type::SELECTOR_ELEMENT) {
+ if (type != selector_type::SELECTOR_TAG) {
return std::string_view(std::get<std::string_view>(value));
}
return std::nullopt;
};
explicit css_selector(selector_type t) : type(t) {}
- explicit css_selector(tag_id_t t) : type(selector_type::SELECTOR_ELEMENT) {
+ explicit css_selector(tag_id_t t) : type(selector_type::SELECTOR_TAG) {
value = t;
}
explicit css_selector(const std::string_view &st, selector_type t = selector_type::SELECTOR_ID) : type(t) {
class hash<rspamd::css::css_selector> {
public:
auto operator() (const rspamd::css::css_selector &sel) const -> auto {
- if (sel.type == rspamd::css::css_selector::selector_type::SELECTOR_ELEMENT) {
+ if (sel.type == rspamd::css::css_selector::selector_type::SELECTOR_TAG) {
return static_cast<std::uint64_t>(std::get<tag_id_t>(sel.value));
}
else {