]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
plugins: fts-solr: solr-response - Fix incremental parsing of XML element data in...
authorStephan Bosch <stephan.bosch@open-xchange.com>
Tue, 8 Oct 2019 16:57:02 +0000 (18:57 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Thu, 9 Jan 2020 12:52:43 +0000 (12:52 +0000)
src/plugins/fts-solr/solr-response.c
src/plugins/fts-solr/test-solr-response.c

index 5a14e43a1723e2df6b6f769bbe6abf266afb5cab..65a6a1fe7809e4d2f0a9eee1093356fe53e9cc80 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <expat.h>
 
+#define MAX_VALUE_LEN 2048
+
 enum solr_xml_response_state {
        SOLR_XML_RESPONSE_STATE_ROOT,
        SOLR_XML_RESPONSE_STATE_RESPONSE,
@@ -34,6 +36,7 @@ struct solr_response_parser {
        enum solr_xml_response_state state;
        enum solr_xml_content_state content_state;
        int depth;
+       string_t *buffer;
 
        uint32_t uid, uidvalidity;
        float score;
@@ -96,6 +99,8 @@ solr_lookup_xml_start(void *context, const char *name, const char **attrs)
                return;
        }
 
+       str_truncate(parser->buffer, 0);
+
        /* response -> result -> doc */
        switch (parser->state) {
        case SOLR_XML_RESPONSE_STATE_ROOT:
@@ -198,10 +203,36 @@ static int solr_lookup_add_doc(struct solr_response_parser *parser)
 static void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
 {
        struct solr_response_parser *parser = context;
+       string_t *buf = parser->buffer;
        int ret;
 
-       if (parser->content_state == SOLR_XML_CONTENT_STATE_ERROR)
+       switch (parser->content_state) {
+       case SOLR_XML_CONTENT_STATE_NONE:
+               break;
+       case SOLR_XML_CONTENT_STATE_UID:
+               if (str_to_uint32(str_c(buf), &parser->uid) < 0 ||
+                   parser->uid == 0) {
+                       i_error("fts_solr: received invalid uid '%s'",
+                               str_c(buf));
+                       parser->content_state = SOLR_XML_CONTENT_STATE_ERROR;
+               }
+               break;
+       case SOLR_XML_CONTENT_STATE_SCORE:
+               parser->score = strtod(str_c(buf), NULL);
+               break;
+       case SOLR_XML_CONTENT_STATE_MAILBOX:
+               parser->mailbox = i_strdup(str_c(buf));
+               break;
+       case SOLR_XML_CONTENT_STATE_NAMESPACE:
+               parser->ns = i_strdup(str_c(buf));
+               break;
+       case SOLR_XML_CONTENT_STATE_UIDVALIDITY:
+               if (str_to_uint32(str_c(buf), &parser->uidvalidity) < 0)
+                       i_error("fts_solr: received invalid uidvalidity");
+               break;
+       case SOLR_XML_CONTENT_STATE_ERROR:
                return;
+       }
 
        i_assert(parser->depth >= (int)parser->state);
 
@@ -231,46 +262,27 @@ static void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
 static void solr_lookup_xml_data(void *context, const char *str, int len)
 {
        struct solr_response_parser *parser = context;
-       char *new_name;
 
        switch (parser->content_state) {
        case SOLR_XML_CONTENT_STATE_NONE:
-               break;
+       case SOLR_XML_CONTENT_STATE_ERROR:
+               /* ignore element data */
+               return;
        case SOLR_XML_CONTENT_STATE_UID:
-               if (str_to_uint32(t_strndup(str, len), &parser->uid) < 0 ||
-                   parser->uid == 0) {
-                       i_error("fts_solr: received invalid uid '%s'",
-                               t_strndup(str, len));
-                       parser->content_state = SOLR_XML_CONTENT_STATE_ERROR;
-               }
-               break;
        case SOLR_XML_CONTENT_STATE_SCORE:
-               T_BEGIN {
-                       parser->score = strtod(t_strndup(str, len), NULL);
-               } T_END;
-               break;
        case SOLR_XML_CONTENT_STATE_MAILBOX:
-               /* this may be called multiple times, for example if input
-                  contains '&' characters */
-               new_name = parser->mailbox == NULL ? i_strndup(str, len) :
-                       i_strconcat(parser->mailbox, t_strndup(str, len), NULL);
-               i_free(parser->mailbox);
-               parser->mailbox = new_name;
-               break;
        case SOLR_XML_CONTENT_STATE_NAMESPACE:
-               new_name = parser->ns == NULL ? i_strndup(str, len) :
-                       i_strconcat(parser->ns, t_strndup(str, len), NULL);
-               i_free(parser->ns);
-               parser->ns = new_name;
-               break;
        case SOLR_XML_CONTENT_STATE_UIDVALIDITY:
-               if (str_to_uint32(t_strndup(str, len),
-                                 &parser->uidvalidity) < 0)
-                       i_error("fts_solr: received invalid uidvalidity");
-               break;
-       case SOLR_XML_CONTENT_STATE_ERROR:
                break;
        }
+
+       if (str_len(parser->buffer) + len > MAX_VALUE_LEN) {
+               i_error("fts_solr: XML element data length out of range");
+               parser->content_state = SOLR_XML_CONTENT_STATE_ERROR;
+               return;
+       }
+
+       str_append_data(parser->buffer, str, len);
 }
 
 struct solr_response_parser *
@@ -286,6 +298,7 @@ solr_response_parser_init(pool_t result_pool, struct istream *input)
                               "fts_solr: Failed to allocate XML parser");
        }
 
+       parser->buffer = str_new(default_pool, 256);
        hash_table_create(&parser->mailboxes, default_pool, 0,
                          str_hash, strcmp);
 
@@ -314,6 +327,7 @@ void solr_response_parser_deinit(struct solr_response_parser **_parser)
        if (parser == NULL)
                return;
 
+       str_free(&parser->buffer);
        hash_table_destroy(&parser->mailboxes);
        XML_ParserFree(parser->xml_parser);
        i_stream_unref(&parser->input);
index 630632d8f4ebf8d060ca46eb7a5c824d2ff607b0..6ddeb48c3cd98c397aff425862e41062a2723878 100644 (file)
@@ -190,7 +190,7 @@ static void test_solr_response_parser(void)
        for (i = 0; i < tests_count; i++) T_BEGIN {
                const struct solr_response_test *test;
                const char *text;
-               unsigned int text_len;
+               unsigned int pos, text_len;
                struct istream *input;
                struct solr_response_parser *parser;
                struct solr_result **box_results;
@@ -218,6 +218,24 @@ static void test_solr_response_parser(void)
                pool_unref(&pool);
                i_stream_unref(&input);
 
+               input = test_istream_create_data(text, text_len);
+               pool = pool_alloconly_create("solr response", 4096);
+               parser = solr_response_parser_init(pool, input);
+
+               ret = 0;
+               for (pos = 0; pos <= text_len && ret == 0; pos++) {
+                       test_istream_set_size(input, pos);
+                       ret = solr_response_parse(parser, &box_results);
+               }
+
+               test_out_reason("parse ok (trickle)", ret > 0, error);
+               if (ret > 0)
+                       test_solr_result(test->results, box_results);
+
+               solr_response_parser_deinit(&parser);
+               pool_unref(&pool);
+               i_stream_unref(&input);
+
                test_end();
 
        } T_END;