#include <expat.h>
+#define MAX_VALUE_LEN 2048
+
enum solr_xml_response_state {
SOLR_XML_RESPONSE_STATE_ROOT,
SOLR_XML_RESPONSE_STATE_RESPONSE,
enum solr_xml_response_state state;
enum solr_xml_content_state content_state;
int depth;
+ string_t *buffer;
uint32_t uid, uidvalidity;
float score;
return;
}
+ str_truncate(parser->buffer, 0);
+
/* response -> result -> doc */
switch (parser->state) {
case SOLR_XML_RESPONSE_STATE_ROOT:
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);
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 *
"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);
if (parser == NULL)
return;
+ str_free(&parser->buffer);
hash_table_destroy(&parser->mailboxes);
XML_ParserFree(parser->xml_parser);
i_stream_unref(&parser->input);
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;
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;