diff options
-rw-r--r-- | src/rcl/rcl_parser.c | 28 | ||||
-rw-r--r-- | src/rcl/rcl_util.c | 54 | ||||
-rw-r--r-- | test/rspamd_rcl_test.c | 11 |
3 files changed, 76 insertions, 17 deletions
diff --git a/src/rcl/rcl_parser.c b/src/rcl/rcl_parser.c index cf5ca76b9..16552d325 100644 --- a/src/rcl/rcl_parser.c +++ b/src/rcl/rcl_parser.c @@ -232,7 +232,7 @@ rspamd_cl_lex_is_atom_end (const guchar c) * @return TRUE if a number has been parsed */ static gboolean -rspamd_cl_lex_json_number (struct rspamd_cl_parser *parser, +rspamd_cl_lex_number (struct rspamd_cl_parser *parser, struct rspamd_cl_chunk *chunk, rspamd_cl_object_t *obj, GError **err) { const guchar *p = chunk->pos, *c = chunk->pos; @@ -362,10 +362,10 @@ rspamd_cl_lex_json_number (struct rspamd_cl_parser *parser, p ++; goto set_obj; } - else if (chunk->end - p > 3) { + else if (chunk->end - p >= 3) { if (g_ascii_tolower (p[0]) == 'm' && g_ascii_tolower (p[1]) == 'i' && - g_ascii_tolower (p[2]) == 'm') { + g_ascii_tolower (p[2]) == 'n') { /* Minutes */ if (!need_double) { need_double = TRUE; @@ -413,14 +413,15 @@ rspamd_cl_lex_json_number (struct rspamd_cl_parser *parser, case 'W': case 'Y': case 'y': - if (p == chunk->end - 1 || rspamd_cl_lex_is_atom_end (*++p)) { + if (p == chunk->end - 1 || rspamd_cl_lex_is_atom_end (p[1])) { if (!need_double) { need_double = TRUE; dv = lv; } is_date = TRUE; - rspamd_cl_chunk_skipc (chunk, *p); dv *= rspamd_cl_lex_time_multiplier (*p); + rspamd_cl_chunk_skipc (chunk, *p); + p ++; goto set_obj; } break; @@ -668,12 +669,13 @@ rspamd_cl_parse_key (struct rspamd_cl_parser *parser, HASH_FIND_STR (container, nobj->key, tobj); if (tobj != NULL) { /* Just insert a new object as the next element */ - tobj->next = nobj; - } - else { - HASH_ADD_KEYPTR (hh, container, nobj->key, strlen (nobj->key), nobj); + LL_PREPEND (tobj, nobj); + HASH_DELETE (hh, container, tobj); } + HASH_ADD_KEYPTR (hh, container, nobj->key, strlen (nobj->key), nobj); + parser->stack->obj->value.ov = container; + parser->cur_obj = nobj; return TRUE; @@ -783,6 +785,8 @@ rspamd_cl_state_machine (struct rspamd_cl_parser *parser, GError **err) if (parser->stack->obj->type == RSPAMD_CL_ARRAY) { /* Object must be allocated */ obj = rspamd_cl_object_new (); + parser->cur_obj = obj; + LL_PREPEND (parser->stack->obj->value.ov, parser->cur_obj); } else { /* Object has been already allocated */ @@ -797,8 +801,8 @@ rspamd_cl_state_machine (struct rspamd_cl_parser *parser, GError **err) parser->state = RSPAMD_RCL_STATE_ERROR; return FALSE; } - obj->value.sv = g_malloc (chunk->pos - c); - rspamd_strlcpy (obj->value.sv, c + 1, chunk->pos - c); + obj->value.sv = g_malloc (chunk->pos - c - 1); + rspamd_strlcpy (obj->value.sv, c + 1, chunk->pos - c - 1); rspamd_cl_unescape_json_string (obj->value.sv); obj->type = RSPAMD_CL_STRING; parser->state = RSPAMD_RCL_STATE_AFTER_VALUE; @@ -845,7 +849,7 @@ rspamd_cl_state_machine (struct rspamd_cl_parser *parser, GError **err) } /* Parse atom */ if (g_ascii_isdigit (*p) || *p == '-') { - if (!rspamd_cl_lex_json_number (parser, chunk, obj, err)) { + if (!rspamd_cl_lex_number (parser, chunk, obj, err)) { if (parser->state == RSPAMD_RCL_STATE_ERROR) { return FALSE; } diff --git a/src/rcl/rcl_util.c b/src/rcl/rcl_util.c index 3216a27d8..1c9d6a652 100644 --- a/src/rcl/rcl_util.c +++ b/src/rcl/rcl_util.c @@ -31,8 +31,8 @@ */ -void -rspamd_cl_obj_free (rspamd_cl_object_t *obj) +static void +rspamd_cl_obj_free_internal (rspamd_cl_object_t *obj, gboolean allow_rec) { rspamd_cl_object_t *sub, *tmp; @@ -48,23 +48,33 @@ rspamd_cl_obj_free (rspamd_cl_object_t *obj) sub = obj->value.ov; while (sub != NULL) { tmp = sub->next; - rspamd_cl_obj_free (sub); + rspamd_cl_obj_free_internal (sub, FALSE); sub = tmp; } } else if (obj->type == RSPAMD_CL_OBJECT) { HASH_ITER (hh, obj->value.ov, sub, tmp) { HASH_DELETE (hh, obj->value.ov, sub); - rspamd_cl_obj_free (sub); + rspamd_cl_obj_free_internal (sub, TRUE); } } tmp = obj->next; g_slice_free1 (sizeof (rspamd_cl_object_t), obj); obj = tmp; + + if (!allow_rec) { + break; + } } } void +rspamd_cl_obj_free (rspamd_cl_object_t *obj) +{ + rspamd_cl_obj_free_internal (obj, TRUE); +} + +void rspamd_cl_unescape_json_string (gchar *str) { gchar *t = str, *h = str; @@ -112,6 +122,7 @@ rspamd_cl_unescape_json_string (gchar *str) uval += h[i] - 'A' + 10; } } + h += 3; /* Encode */ if(uval < 0x80) { t[0] = (char)uval; @@ -143,9 +154,44 @@ rspamd_cl_unescape_json_string (gchar *str) *t++ = '?'; break; } + h ++; } else { *t++ = *h++; } } } + +rspamd_cl_object_t* +rspamd_cl_parser_get_object (struct rspamd_cl_parser *parser, GError **err) +{ + if (parser->state != RSPAMD_RCL_STATE_INIT && parser->state != RSPAMD_RCL_STATE_ERROR) { + return parser->top_obj; + } + + return NULL; +} + +void +rspamd_cl_parser_free (struct rspamd_cl_parser *parser) +{ + struct rspamd_cl_stack *stack, *stmp; + struct rspamd_cl_macro *macro, *mtmp; + struct rspamd_cl_chunk *chunk, *ctmp; + + if (parser->top_obj != NULL) { + rspamd_cl_obj_free (parser->top_obj); + } + + LL_FOREACH_SAFE (parser->stack, stack, stmp) { + g_slice_free1 (sizeof (struct rspamd_cl_stack), stack); + } + HASH_ITER (hh, parser->macroes, macro, mtmp) { + g_slice_free1 (sizeof (struct rspamd_cl_macro), macro); + } + LL_FOREACH_SAFE (parser->chunks, chunk, ctmp) { + g_slice_free1 (sizeof (struct rspamd_cl_chunk), chunk); + } + + g_slice_free1 (sizeof (struct rspamd_cl_parser), parser); +} diff --git a/test/rspamd_rcl_test.c b/test/rspamd_rcl_test.c index 01b3ba835..695002de5 100644 --- a/test/rspamd_rcl_test.c +++ b/test/rspamd_rcl_test.c @@ -23,6 +23,7 @@ #include "../src/config.h" #include "../src/rcl/rcl.h" +#include "../src/main.h" #include "tests.h" const gchar *rcl_test_valid[] = { @@ -33,7 +34,7 @@ const gchar *rcl_test_valid[] = { "\"key1\": \"value;\"" "}\n", /* Nginx like */ - "section1 { param1 = value; param2 = value, param3 = [\"value1\", 100500]}\n" + "section1 { param1 = value; param2 = value, param3 = [\"value1\", value2, 100500]}\n" "section2 { param1 = {key = value}, param1 = [\"key\"]}", /* Numbers */ "key = 1s\n" @@ -57,6 +58,7 @@ rspamd_rcl_test_func (void) struct rspamd_cl_parser *parser; rspamd_cl_object_t *obj; const gchar **cur; + guchar *emitted; GError *err = NULL; cur = rcl_test_valid; @@ -65,6 +67,13 @@ rspamd_rcl_test_func (void) g_assert (parser != NULL); rspamd_cl_parser_add_chunk (parser, *cur, strlen (*cur), &err); g_assert_no_error (err); + obj = rspamd_cl_parser_get_object (parser, &err); + g_assert_no_error (err); + emitted = rspamd_cl_object_emit (obj, RSPAMD_CL_EMIT_JSON); + g_assert (emitted != NULL); + msg_info ("got json output: %s", emitted); + g_free (emitted); + rspamd_cl_parser_free (parser); cur ++; } |