commit 7954b67: [Porject] Css: Rework functions parsing

Vsevolod Stakhov vsevolod at highsecure.ru
Wed Mar 3 21:49:06 UTC 2021


Author: Vsevolod Stakhov
Date: 2021-03-03 21:41:55 +0000
URL: https://github.com/rspamd/rspamd/commit/7954b67e2d51a94e47e89767c2382da490973f9f (HEAD -> master)

[Porject] Css: Rework functions parsing

---
 src/libserver/css/css_parser.cxx    | 33 +++++++++++++++++++++---
 src/libserver/css/css_parser.hxx    | 22 ++++++++++++++--
 src/libserver/css/css_tokeniser.cxx | 51 ++++++++++++++++++++++---------------
 test/lua/unit/css.lua               | 25 ++++++++++++++++++
 4 files changed, 105 insertions(+), 26 deletions(-)

diff --git a/src/libserver/css/css_parser.cxx b/src/libserver/css/css_parser.cxx
index e4a8159f1..014ddf680 100644
--- a/src/libserver/css/css_parser.cxx
+++ b/src/libserver/css/css_parser.cxx
@@ -27,11 +27,11 @@ namespace rspamd::css {
 const css_consumed_block css_parser_eof_block{};
 
 auto css_consumed_block::attach_block(consumed_block_ptr &&block) -> bool {
-	if (content.index() == 0) {
+	if (std::holds_alternative<std::monostate>(content)) {
 		/* Switch from monostate */
 		content = std::vector<consumed_block_ptr>();
 	}
-	else if (content.index() == 2) {
+	else if (!std::holds_alternative<std::vector<consumed_block_ptr>>(content)) {
 		/* A single component, cannot attach a block ! */
 		return false;
 	}
@@ -42,6 +42,17 @@ auto css_consumed_block::attach_block(consumed_block_ptr &&block) -> bool {
 	return true;
 }
 
+auto css_consumed_block::add_function_argument(consumed_block_ptr &&block)  -> bool {
+	if (!std::holds_alternative<css_function_block>(content)) {
+		return false;
+	}
+
+	auto &&func_bloc = std::get<css_function_block>(content);
+	func_bloc.args.push_back(std::move(block));
+
+	return true;
+}
+
 auto css_consumed_block::token_type_str(void) const -> const char *
 {
 	const auto *ret = "";
@@ -106,6 +117,18 @@ auto css_consumed_block::debug_str(void) -> std::string {
 					/* Empty block */
 					ret += R"("empty")";
 				}
+				else if constexpr (std::is_same_v<T, css_function_block>) {
+					/* Empty block */
+					ret += R"({ "function:" {"name": )";
+					ret += "\"" + arg.function.debug_token_str() + "\"";
+					ret += R"("arguments:"  [)";
+					for (const auto &block : arg.args) {
+						ret += "{";
+						ret += block->debug_str();
+						ret += "}, ";
+					}
+					ret += "]}";
+				}
 				else {
 					/* Single element block */
 					ret += "\"" + arg.debug_token_str() + "\"";
@@ -214,9 +237,13 @@ auto css_parser::function_consumer(std::unique_ptr<css_consumed_block> &top) ->
 			ret = true;
 			want_more = false;
 			break;
+		case css_parser_token::token_type::comma_token:
+		case css_parser_token::token_type::delim_token:
+		case css_parser_token::token_type::obrace_token:
+			break;
 		default:
 			/* Attach everything to the function block */
-			top->attach_block(std::make_unique<css_consumed_block>(
+			top->add_function_argument(std::make_unique<css_consumed_block>(
 					css::css_consumed_block::parser_tag_type::css_function_arg,
 					std::move(next_token)));
 			break;
diff --git a/src/libserver/css/css_parser.hxx b/src/libserver/css/css_parser.hxx
index de982525a..7530730e7 100644
--- a/src/libserver/css/css_parser.hxx
+++ b/src/libserver/css/css_parser.hxx
@@ -51,6 +51,14 @@ public:
 	};
 	using consumed_block_ptr = std::unique_ptr<css_consumed_block>;
 
+	struct css_function_block {
+		css_parser_token function;
+		std::vector<consumed_block_ptr> args;
+
+		css_function_block(css_parser_token &&tok) :
+			function(std::forward<css_parser_token>(tok)) {}
+	};
+
 	css_consumed_block() : tag(parser_tag_type::css_eof_block) {}
 	css_consumed_block(parser_tag_type tag) : tag(tag) {
 		if (tag == parser_tag_type::css_top_block ||
@@ -64,10 +72,19 @@ public:
 	}
 	/* Construct a block from a single lexer token (for trivial blocks) */
 	explicit css_consumed_block(parser_tag_type tag, css_parser_token &&tok) :
-			tag(tag), content(std::move(tok)) {}
+			tag(tag) {
+		if (tag == parser_tag_type::css_function) {
+			content = css_function_block{std::move(tok)};
+		}
+		else {
+			content = std::move(tok);
+		}
+	}
 
 	/* Attach a new block to the compound block, consuming block inside */
 	auto attach_block(consumed_block_ptr &&block) -> bool;
+	/* Attach a new argument to the compound function block, consuming block inside */
+	auto add_function_argument(consumed_block_ptr &&block) -> bool;
 
 	auto assign_token(css_parser_token &&tok) -> void {
 		content = std::move(tok);
@@ -137,7 +154,8 @@ public:
 private:
 	std::variant<std::monostate,
 			std::vector<consumed_block_ptr>,
-			css_parser_token> content;
+			css_parser_token,
+			css_function_block> content;
 };
 
 extern const css_consumed_block css_parser_eof_block;
diff --git a/src/libserver/css/css_tokeniser.cxx b/src/libserver/css/css_tokeniser.cxx
index f3a2767bd..1d6e89df7 100644
--- a/src/libserver/css/css_tokeniser.cxx
+++ b/src/libserver/css/css_tokeniser.cxx
@@ -246,34 +246,43 @@ auto css_tokeniser::consume_ident() -> struct css_parser_token
 				auto j = i + 1;
 
 				while (j < input.size() && g_ascii_isspace(input[j])) {
-					j ++;
+					j++;
 				}
 
-				if (input[j] == '"' || input[j] == '\'') {
-					/* Function token */
-					return maybe_escape_sv(j + 1,
-							css_parser_token::token_type::function_token);
-				}
-				else {
-					/* Consume URL token */
-					while (j < input.size() && input[j] != ')') {
-						j ++;
-					}
-
-					if (input[j] == ')') {
-						/* Valid url token */
-						return maybe_escape_sv(j + 1,
-								css_parser_token::token_type::url_token);
+				if (input.size() > 3 && input.substr(0, 3) == "url") {
+					if (input[j] == '"' || input[j] == '\'') {
+						/* Function token */
+						auto ret = maybe_escape_sv(i,
+								css_parser_token::token_type::function_token);
+						return ret;
 					}
 					else {
-						/* Incomplete url token */
-						auto ret = maybe_escape_sv(j,
-								css_parser_token::token_type::url_token);
+						/* Consume URL token */
+						while (j < input.size() && input[j] != ')') {
+							j++;
+						}
 
-						ret.flags |= css_parser_token::flag_bad_string;
-						return ret;
+						if (input[j] == ')') {
+							/* Valid url token */
+							auto ret = maybe_escape_sv(j + 1,
+									css_parser_token::token_type::url_token);
+							return ret;
+						}
+						else {
+							/* Incomplete url token */
+							auto ret = maybe_escape_sv(j,
+									css_parser_token::token_type::url_token);
+
+							ret.flags |= css_parser_token::flag_bad_string;
+							return ret;
+						}
 					}
 				}
+				else {
+					auto ret = maybe_escape_sv(i,
+							css_parser_token::token_type::function_token);
+					return ret;
+				}
 			}
 			else if (c == '-' && allow_middle_minus) {
 				i++;
diff --git a/test/lua/unit/css.lua b/test/lua/unit/css.lua
index a5a8f533f..4bd78b244 100644
--- a/test/lua/unit/css.lua
+++ b/test/lua/unit/css.lua
@@ -97,6 +97,31 @@ body {
     width: 100%;
   }
 }
+]],
+[[
+/* Colors */
+* { color: hsl(0, 100%, 50%) }   /* red */
+* { color: hsl(120, 100%, 50%) } /* lime */
+* { color: hsl(120, 100%, 25%) } /* dark green */
+* { color: hsl(120, 100%, 75%) } /* light green */
+* { color: hsl(120, 75%, 75%) }  /* pastel green, and so on */
+em { color: #f00 }              /* #rgb */
+em { color: #ff0000 }           /* #rrggbb */
+em { color: rgb(255,0,0) }
+em { color: rgb(100%, 0%, 0%) }
+body {color: black; background: white }
+h1 { color: maroon }
+h2 { color: olive }
+em { color: rgb(255,0,0) }       /* integer range 0 - 255 */
+em { color: rgb(300,0,0) }       /* clipped to rgb(255,0,0) */
+em { color: rgb(255,-10,0) }     /* clipped to rgb(255,0,0) */
+em { color: rgb(110%, 0%, 0%) }  /* clipped to rgb(100%,0%,0%) */
+em { color: rgb(255,0,0) }      /* integer range 0 - 255 */
+em { color: rgba(255,0,0,1)     /* the same, with explicit opacity of 1 */
+em { color: rgb(100%,0%,0%) }   /* float range 0.0% - 100.0% */
+em { color: rgba(100%,0%,0%,1) } /* the same, with explicit opacity of 1 */
+p { color: rgba(0,0,255,0.5) }        /* semi-transparent solid blue */
+p { color: rgba(100%, 50%, 0%, 0.1) } /* very transparent solid orange */
 ]]
   }
   local NULL = ffi.new 'void*'


More information about the Commits mailing list