}
/* Note: these have to match the event_filter_append_escaped() behavior */
<string>[^\\"]+ { str_append(str_buf, yytext); }
-<string>\\\\ { str_append_c(str_buf, '\\'); }
-<string>\\\" { str_append_c(str_buf, '"'); }
+<string>\\\\ { str_append(str_buf, yytext); }
+<string>\\\" { str_append(str_buf, yytext); }
<string>\\. { str_append(str_buf, yytext); }
[Aa][Nn][Dd] { return AND; }
#include <ctype.h>
#include "lib.h"
+#include "strescape.h"
#include "str-parse.h"
#include "wildcard-match.h"
#include "lib-event-private.h"
switch (type) {
case EVENT_FILTER_NODE_TYPE_LOGIC:
i_unreached();
- case EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD:
- node->str = p_strdup(state->pool, b);
- if (wildcard_is_literal(node->str))
+ case EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD: {
+ if (wildcard_is_escaped_literal(b)) {
node->type = EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT;
+ node->str = str_unescape(p_strdup(state->pool, b));
+ } else {
+ node->str = p_strdup(state->pool, b);
+ }
break;
+ }
case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION: {
const char *colon = strrchr(b, ':');
- const char *file;
+ char *file;
uintmax_t line;
/* split "filename:line-number", but also handle "filename" */
line = 0;
}
- node->str = file;
+ node->str = str_unescape(file);
node->intmax = line;
break;
}
case EVENT_FILTER_NODE_TYPE_EVENT_CATEGORY:
if (!event_filter_category_to_log_type(b, &node->category.log_type)) {
- node->category.name = p_strdup(state->pool, b);
+ node->category.name = str_unescape(p_strdup(state->pool, b));
node->category.ptr = event_category_find_registered(b);
}
break;
- case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
+ case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD: {
+ char *b_duped = p_strdup(state->pool, b);
node->field.key = p_strdup(state->pool, a);
- node->field.value.str = p_strdup(state->pool, b);
+ node->field.value.str = b_duped;
node->field.value_type = EVENT_FIELD_VALUE_TYPE_STR;
/* Filter currently supports only comparing strings
break;
}
- if (wildcard_is_literal(node->field.value.str))
+ if (wildcard_is_escaped_literal(b)) {
node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT;
- else if (strspn(b, "0123456789*?") == strlen(b))
+ str_unescape(b_duped);
+ } else if (strspn(b, "0123456789*?") == strlen(b)) {
node->type = EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD;
+ }
}
break;
+ }
case EVENT_FILTER_NODE_TYPE_EVENT_NAME_EXACT:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
;
key : TOKEN { $$ = $1; }
- | STRING { $$ = $1; }
+ | STRING { $$ = str_unescape(t_strdup_noconst($1)); }
;
value : TOKEN { $$ = $1; }
#include "event-filter.h"
#include "event-filter-private.h"
-/* Note: this has to match the regexp behavior in the event filter lexer file */
-#define event_filter_append_escaped(dst, str) \
- str_append_escaped((dst), (str), strlen(str))
-
enum event_filter_code {
EVENT_FILTER_CODE_NAME = 'n',
EVENT_FILTER_CODE_SOURCE = 's',
event_filter_merge_with_context_internal(dest, src, new_context, TRUE);
}
+static void
+event_filter_append_escaped(string_t *dest, const char *src, bool wildcard)
+{
+ if (!wildcard)
+ str_append_escaped(dest, src, strlen(src));
+ else {
+ /* src is already escaped */
+ str_append(dest, src);
+ }
+}
+
static const char *
event_filter_export_query_expr_op(enum event_filter_node_op op)
{
str_append(dest, "event");
str_append(dest, event_filter_export_query_expr_op(node->op));
str_append_c(dest, '"');
- event_filter_append_escaped(dest, node->str);
+ event_filter_append_escaped(dest, node->str,
+ node->type == EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD);
str_append_c(dest, '"');
break;
case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION:
str_append(dest, "source_location");
str_append(dest, event_filter_export_query_expr_op(node->op));
str_append_c(dest, '"');
- event_filter_append_escaped(dest, node->str);
+ event_filter_append_escaped(dest, node->str, FALSE);
if (node->intmax != 0)
str_printfa(dest, ":%ju", node->intmax);
str_append_c(dest, '"');
str_append(dest, event_filter_export_query_expr_op(node->op));
if (node->category.name != NULL) {
str_append_c(dest, '"');
- event_filter_append_escaped(dest, node->category.name);
+ event_filter_append_escaped(dest, node->category.name, FALSE);
str_append_c(dest, '"');
} else
str_append(dest, event_filter_category_from_log_type(node->category.log_type));
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_WILDCARD:
case EVENT_FILTER_NODE_TYPE_EVENT_FIELD_NUMERIC_WILDCARD:
str_append_c(dest, '"');
- event_filter_append_escaped(dest, node->field.key);
+ event_filter_append_escaped(dest, node->field.key, FALSE);
str_append_c(dest, '"');
str_append(dest, event_filter_export_query_expr_op(node->op));
str_append_c(dest, '"');
- event_filter_append_escaped(dest, node->field.value.str);
+ event_filter_append_escaped(dest, node->field.value.str,
+ node->type != EVENT_FILTER_NODE_TYPE_EVENT_FIELD_EXACT);
str_append_c(dest, '"');
break;
}
array_foreach_elem(&field->value.strlist, value) {
*seen = TRUE;
match = use_strcmp ? strcasecmp(value, wanted_value) == 0 :
- wildcard_match_icase(value, wanted_value);
+ wildcard_match_escaped_icase(value, wanted_value);
if (match)
return TRUE;
}
if (use_strcmp)
return strcasecmp(field->value.str, wanted_field->value.str) == 0;
else
- return wildcard_match_icase(field->value.str, wanted_field->value.str);
+ return wildcard_match_escaped_icase(field->value.str, wanted_field->value.str);
case EVENT_FIELD_VALUE_TYPE_INTMAX:
if (node->ambiguous_unit) {
if (!node->warned_ambiguous_unit) {
} else {
char tmp[MAX_INT_STRLEN];
i_snprintf(tmp, sizeof(tmp), "%jd", field->value.intmax);
- return wildcard_match_icase(tmp, wanted_field->value.str);
+ return wildcard_match_escaped_icase(tmp, wanted_field->value.str);
}
case EVENT_FIELD_VALUE_TYPE_TIMEVAL: {
/* Filtering for timeval fields is not implemented. */
}
bool ret;
T_BEGIN {
- ret = wildcard_match_icase(net_ip2addr(&field->value.ip),
- wanted_field->value.str);
+ ret = wildcard_match_escaped_icase(net_ip2addr(&field->value.ip),
+ wanted_field->value.str);
} T_END;
return ret;
case EVENT_FIELD_VALUE_TYPE_STRLIST:
strcmp(event->sending_name, node->str) == 0;
case EVENT_FILTER_NODE_TYPE_EVENT_NAME_WILDCARD:
return (event->sending_name != NULL) &&
- wildcard_match(event->sending_name, node->str);
+ wildcard_match_escaped(event->sending_name, node->str);
case EVENT_FILTER_NODE_TYPE_EVENT_SOURCE_LOCATION:
return !((source_linenum != node->intmax &&
node->intmax != 0) ||
event_filter_export(filter, tmp);
- test_out_quiet(t_strdup_printf("input: %s", input),
+ test_out_quiet(t_strdup_printf("input: %s (%s)", input, str_c(tmp)),
strcmp(exp, str_c(tmp)) == 0);
} else {
- test_out_quiet(t_strdup_printf("input: %s", input),
+ test_out_quiet(t_strdup_printf("input: %s (%s)", input, error),
str_begins_with(error, exp));
}
#include "ioloop.h"
#include "event-filter-private.h"
+static void test_event_filter_strings(void)
+{
+ struct event_filter *filter;
+ const char *error;
+ const struct failure_context failure_ctx = {
+ .type = LOG_TYPE_DEBUG
+ };
+
+ test_begin("event filter: strings");
+
+ struct event *e = event_create(NULL);
+ event_add_str(e, "str", "hello \\world");
+
+ struct event *e2 = event_create(NULL);
+ event_add_str(e2, "str", "hello *world");
+
+ /* "quoting" works with \escaping */
+ filter = event_filter_create();
+ test_assert(event_filter_parse("str = \"hello \\\\world\"", filter, &error) == 0);
+ test_assert(event_filter_match(filter, e, &failure_ctx));
+ test_assert(!event_filter_match(filter, e2, &failure_ctx));
+ event_filter_unref(&filter);
+
+ /* wildcards work inside quotes */
+ filter = event_filter_create();
+ test_assert(event_filter_parse("str = \"hello *world\"", filter, &error) == 0);
+ test_assert(event_filter_match(filter, e, &failure_ctx));
+ test_assert(event_filter_match(filter, e2, &failure_ctx));
+ event_filter_unref(&filter);
+
+ /* escaped wildcard is an exact string */
+ filter = event_filter_create();
+ test_assert(event_filter_parse("str = \"hello \\*world\"", filter, &error) == 0);
+ test_assert(!event_filter_match(filter, e, &failure_ctx));
+ test_assert(event_filter_match(filter, e2, &failure_ctx));
+ event_filter_unref(&filter);
+
+ event_unref(&e);
+ event_unref(&e2);
+ test_end();
+}
+
static void test_event_filter_override_parent_fields(void)
{
struct event_filter *filter;
void test_event_filter(void)
{
+ test_event_filter_strings();
test_event_filter_override_parent_fields();
test_event_filter_override_global_fields();
test_event_filter_clear_parent_fields();