solr-connection.c revision 54fcc10af7fb60e495318f7e81652d05eb3e0cad
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* curl: 7.16.0 curl_multi_timeout */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "str.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "strescape.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "solr-connection.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <curl/curl.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include <expat.h>
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenenum solr_xml_response_state {
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen SOLR_XML_RESPONSE_STATE_ROOT,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_RESPONSE_STATE_RESPONSE,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_RESPONSE_STATE_RESULT,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_RESPONSE_STATE_DOC,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_RESPONSE_STATE_CONTENT
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenenum solr_xml_content_state {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_NONE = 0,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_UID,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_SCORE,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_MAILBOX,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_NAMESPACE,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen SOLR_XML_CONTENT_STATE_UIDVALIDITY
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct solr_lookup_xml_context {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum solr_xml_response_state state;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum solr_xml_content_state content_state;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int depth;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uint32_t uid, uidvalidity;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen float score;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *mailbox, *ns;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen solr_uid_map_callback_t *callback;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen void *context;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ARRAY_TYPE(seq_range) *uids;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ARRAY_TYPE(fts_score_map) *scores;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct solr_connection_post {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct solr_connection *conn;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size, pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *url;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int failed:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct solr_connection {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen CURL *curl;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen CURLM *curlm;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char curl_errorbuf[CURL_ERROR_SIZE];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct curl_slist *headers, *headers_post;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen XML_Parser xml_parser;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *url, *last_sent_url;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *http_failure;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int debug:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int posting:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen unsigned int xml_failed:1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic size_t
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_output_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct solr_connection_post *post = context;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size = element_size * nmemb;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* @UNSAFE */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (size > post->size - post->pos)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size = post->size - post->pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memcpy(data, post->data + post->pos, size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen post->pos += size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int solr_xml_parse(struct solr_connection *conn,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const void *data, size_t size, bool done)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen enum XML_Error err;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int line;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (conn->xml_failed)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (XML_Parse(conn->xml_parser, data, size, done))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen err = XML_GetErrorCode(conn->xml_parser);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (err != XML_ERROR_FINISHED) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen line = XML_GetCurrentLineNumber(conn->xml_parser);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_error("fts_solr: Invalid XML input at line %d: %s",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen line, XML_ErrorString(err));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->xml_failed = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic size_t
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_input_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct solr_connection *conn = context;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size = element_size * nmemb;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (void)solr_xml_parse(conn, data, size, FALSE);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic size_t
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_header_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct solr_connection *conn = context;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size = element_size * nmemb;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *p;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t i;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (conn->http_failure != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen for (i = 0, p = data; i < size; i++) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (p[i] == ' ') {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i++;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen break;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (i == size || p[i] < '0' || p[i] > '9')
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->http_failure = i_strndup(p + i, size - i);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct solr_connection *solr_connection_init(const char *url, bool debug)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct solr_connection *conn;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn = i_new(struct solr_connection, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->url = i_strdup(url);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->debug = debug;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->curlm = curl_multi_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->curl = curl_easy_init();
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (conn->curl == NULL || conn->curlm == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_fatal_status(FATAL_OUTOFMEM,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "fts_solr: Failed to allocate curl");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* set global curl options */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_ERRORBUFFER, conn->curl_errorbuf);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (conn->debug)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_VERBOSE, 1L);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_NOPROGRESS, 1L);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_NOSIGNAL, 1L);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_READFUNCTION, curl_output_func);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_WRITEFUNCTION, curl_input_func);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_WRITEDATA, conn);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HEADERFUNCTION, curl_header_func);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HEADERDATA, conn);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->headers = curl_slist_append(NULL, "Content-Type: text/xml");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->headers_post = curl_slist_append(NULL, "Content-Type: text/xml");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conn->headers_post = curl_slist_append(conn->headers_post,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Transfer-Encoding: chunked");
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen conn->headers_post = curl_slist_append(conn->headers_post,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "Expect:");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER, conn->headers);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen conn->xml_parser = XML_ParserCreate("UTF-8");
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen if (conn->xml_parser == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal_status(FATAL_OUTOFMEM,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "fts_solr: Failed to allocate XML parser");
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen return conn;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenvoid solr_connection_deinit(struct solr_connection *conn)
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_slist_free_all(conn->headers);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_slist_free_all(conn->headers_post);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_multi_cleanup(conn->curlm);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_easy_cleanup(conn->curl);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(conn->last_sent_url);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(conn->url);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_free(conn);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen}
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainenvoid solr_connection_http_escape(struct solr_connection *conn, string_t *dest,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen const char *str)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen{
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen char *encoded;
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen encoded = curl_easy_escape(conn->curl, str, 0);
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen str_append(dest, encoded);
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen curl_free(encoded);
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen}
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic const char *attrs_get_name(const char **attrs)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen{
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen for (; *attrs != NULL; attrs += 2) {
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen if (strcmp(attrs[0], "name") == 0)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return attrs[1];
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen }
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen return "";
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen}
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainenstatic void
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainensolr_lookup_xml_start(void *context, const char *name, const char **attrs)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct solr_lookup_xml_context *ctx = context;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char *name_attr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->depth >= (int)ctx->state);
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->depth++;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (ctx->depth - 1 > (int)ctx->state) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen /* skipping over unwanted elements */
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen /* response -> result -> doc */
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen switch (ctx->state) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SOLR_XML_RESPONSE_STATE_ROOT:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(name, "response") == 0)
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->state++;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen break;
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen case SOLR_XML_RESPONSE_STATE_RESPONSE:
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen if (strcmp(name, "result") == 0)
9a107dedb8f35727c21b3d1d54475d33f6e2eb1fTimo Sirainen ctx->state++;
9c7e765845357342923e16351181091028e5930fTimo Sirainen break;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen case SOLR_XML_RESPONSE_STATE_RESULT:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (strcmp(name, "doc") == 0) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->state++;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen ctx->uid = 0;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen ctx->score = 0;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen i_free_and_null(ctx->mailbox);
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen i_free_and_null(ctx->ns);
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen ctx->uidvalidity = 0;
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen break;
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo Sirainen case SOLR_XML_RESPONSE_STATE_DOC:
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen name_attr = attrs_get_name(attrs);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (strcmp(name_attr, "uid") == 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UID;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen else if (strcmp(name_attr, "score") == 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_SCORE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen else if (strcmp(name_attr, "box") == 0)
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_MAILBOX;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen else if (strcmp(name_attr, "ns") == 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NAMESPACE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen else if (strcmp(name_attr, "uidv") == 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UIDVALIDITY;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen else
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen break;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->state++;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SOLR_XML_RESPONSE_STATE_CONTENT:
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen break;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void solr_lookup_add_doc(struct solr_lookup_xml_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen struct fts_score_map *score;
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen if (ctx->uid == 0) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen i_error("fts_solr: Query didn't return uid");
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->callback != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->mailbox == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts_solr: Query didn't return mailbox");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (!ctx->callback(ctx->ns, ctx->mailbox, ctx->uidvalidity,
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen &ctx->uid, ctx->context))
ea9fd7f876643e985946a2563140359064819b8eTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen seq_range_array_add(ctx->uids, 0, ctx->uid);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ctx->scores != NULL && ctx->score != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen score = array_append_space(ctx->scores);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen score->uid = ctx->uid;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen score->score = ctx->score;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen }
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct solr_lookup_xml_context *ctx = context;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_assert(ctx->depth >= (int)ctx->state);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen if (ctx->depth == (int)ctx->state) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ctx->state == SOLR_XML_RESPONSE_STATE_DOC)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen solr_lookup_add_doc(ctx);
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen ctx->state--;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NONE;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen }
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->depth--;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen}
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic int uint32_parse(const char *str, int len, uint32_t *value_r)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen uint32_t value = 0;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen int i;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen for (i = 0; i < len; i++) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen if (str[i] < '0' || str[i] > '9')
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen break;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen value = value*10 + str[i]-'0';
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen if (i != len)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return -1;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen *value_r = value;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return 0;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic void solr_lookup_xml_data(void *context, const char *str, int len)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct solr_lookup_xml_context *ctx = context;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen char *new_name;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen switch (ctx->content_state) {
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen case SOLR_XML_CONTENT_STATE_NONE:
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen break;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen case SOLR_XML_CONTENT_STATE_UID:
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen if (uint32_parse(str, len, &ctx->uid) < 0)
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen i_error("fts_solr: received invalid uid");
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen break;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen case SOLR_XML_CONTENT_STATE_SCORE:
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen T_BEGIN {
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen ctx->score = strtod(t_strndup(str, len), NULL);
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen } T_END;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen break;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen case SOLR_XML_CONTENT_STATE_MAILBOX:
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen /* this may be called multiple times, for example if input
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen contains '&' characters */
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen new_name = ctx->mailbox == NULL ? i_strndup(str, len) :
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_strconcat(ctx->mailbox, t_strndup(str, len), NULL);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_free(ctx->mailbox);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->mailbox = new_name;
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen break;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen case SOLR_XML_CONTENT_STATE_NAMESPACE:
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen new_name = ctx->ns == NULL ? i_strndup(str, len) :
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_strconcat(ctx->ns, t_strndup(str, len), NULL);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen i_free(ctx->ns);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->ns = new_name;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case SOLR_XML_CONTENT_STATE_UIDVALIDITY:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uint32_parse(str, len, &ctx->uidvalidity) < 0)
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen i_error("fts_solr: received invalid uidvalidity");
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen break;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainenint solr_connection_select(struct solr_connection *conn, const char *query,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen solr_uid_map_callback_t *callback, void *context,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ARRAY_TYPE(seq_range) *uids,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ARRAY_TYPE(fts_score_map) *scores)
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen{
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct solr_lookup_xml_context solr_lookup_context;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen CURLcode ret;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen long httpret;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen i_assert(!conn->posting);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen memset(&solr_lookup_context, 0, sizeof(solr_lookup_context));
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen solr_lookup_context.uids = uids;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen solr_lookup_context.scores = scores;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen solr_lookup_context.callback = callback;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen solr_lookup_context.context = context;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen i_free_and_null(conn->http_failure);
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen conn->xml_failed = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen XML_ParserReset(conn->xml_parser, "UTF-8");
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen XML_SetElementHandler(conn->xml_parser,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen solr_lookup_xml_start, solr_lookup_xml_end);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen XML_SetCharacterDataHandler(conn->xml_parser, solr_lookup_xml_data);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen XML_SetUserData(conn->xml_parser, &solr_lookup_context);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* curl v7.16 and older don't strdup() the URL */
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_free(conn->last_sent_url);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen conn->last_sent_url = i_strconcat(conn->url, "select?", query, NULL);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_URL, conn->last_sent_url);
8bb360f9e5de1c25e4f875205bb06e8bf15dae14Timo Sirainen ret = curl_easy_perform(conn->curl);
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen if (ret != 0) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_error("fts_solr: HTTP GET failed: %s",
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen conn->curl_errorbuf);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return -1;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (httpret != 200) {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen i_error("fts_solr: Lookup failed: %s", conn->http_failure);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen ret = -1;
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen }
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen return solr_xml_parse(conn, NULL, 0, TRUE);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen}
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainenstruct solr_connection_post *
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainensolr_connection_post_begin(struct solr_connection *conn)
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen{
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen struct solr_connection_post *post;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen CURLMcode merr;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen post = i_new(struct solr_connection_post, 1);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen post->conn = conn;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_assert(!conn->posting);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen conn->posting = TRUE;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_free_and_null(conn->http_failure);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_READDATA, post);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen merr = curl_multi_add_handle(conn->curlm, conn->curl);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (merr != CURLM_OK) {
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_error("fts_solr: curl_multi_add_handle() failed: %s",
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen curl_multi_strerror(merr));
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen post->failed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* curl v7.16 and older don't strdup() the URL */
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen post->url = i_strconcat(conn->url, "update", NULL);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_URL, post->url);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen conn->headers_post);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_POST, (long)1);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen XML_ParserReset(conn->xml_parser, "UTF-8");
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen return post;
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainenvoid solr_connection_post_more(struct solr_connection_post *post,
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen const unsigned char *data, size_t size)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen fd_set fdread;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen fd_set fdwrite;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen fd_set fdexcep;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen struct timeval timeout_tv;
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen long timeout;
ced118ac5caf6fe83d34339c2c65c63b2aa768acTimo Sirainen CURLMsg *msg;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen CURLMcode merr;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen int ret, handles, maxfd, n;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
7bd6001d84ecc1792ddfd54fe8efa63c509d90b1Timo Sirainen i_assert(post->conn->posting);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (post->failed)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen post->data = data;
9a56220167d02bbcb66a81b7553f4eb4da939945Timo Sirainen post->size = size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen post->pos = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (;;) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen merr = curl_multi_perform(post->conn->curlm, &handles);
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen if (merr == CURLM_CALL_MULTI_PERFORM)
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen continue;
8754bb7a1f24705ffa5434f9e10d57e0b3b88d6eTimo Sirainen if (merr != CURLM_OK) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_error("fts_solr: curl_multi_perform() failed: %s",
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen curl_multi_strerror(merr));
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen break;
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen }
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if ((post->pos == post->size && post->size != 0) ||
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen (handles == 0 && post->size == 0)) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen /* everything sent successfully */
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen return;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen }
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen msg = curl_multi_info_read(post->conn->curlm, &n);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (msg != NULL && msg->msg == CURLMSG_DONE &&
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen msg->data.result != CURLE_OK) {
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen i_error("fts_solr: curl post failed: %s",
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen curl_easy_strerror(msg->data.result));
9a099a65160987349f441c82ab0e38f32b747adbTimo Sirainen break;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* everything wasn't sent - wait. just use select,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen since libcurl interface is easiest with it. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_ZERO(&fdread);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_ZERO(&fdwrite);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen FD_ZERO(&fdexcep);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen merr = curl_multi_fdset(post->conn->curlm, &fdread, &fdwrite,
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen &fdexcep, &maxfd);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if (merr != CURLM_OK) {
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_error("fts_solr: curl_multi_fdset() failed: %s",
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen curl_multi_strerror(merr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen i_assert(maxfd >= 0);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen merr = curl_multi_timeout(post->conn->curlm, &timeout);
d3eff05aaa4c2bc0a7580ee87a54f6693f4a8241Timo Sirainen if (merr != CURLM_OK) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts_solr: curl_multi_timeout() failed: %s",
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen curl_multi_strerror(merr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (timeout < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen timeout_tv.tv_sec = 1;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen timeout_tv.tv_usec = 0;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen } else {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen timeout_tv.tv_sec = timeout / 1000;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen timeout_tv.tv_usec = (timeout % 1000) * 1000;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout_tv);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts_solr: select() failed: %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen }
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen post->failed = TRUE;
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen}
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainenint solr_connection_post_end(struct solr_connection_post *post)
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen{
38df0cacce475112991e60d796f8f2105c616f01Timo Sirainen struct solr_connection *conn = post->conn;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen long httpret;
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen int ret = post->failed ? -1 : 0;
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen i_assert(conn->posting);
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen solr_connection_post_more(post, NULL, 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen if (httpret != 200 && ret == 0) {
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen i_error("fts_solr: Indexing failed: %s", conn->http_failure);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = -1;
d77c309fccbc6a7594f8cb08fb01009fa613c568Timo Sirainen }
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_READDATA, NULL);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_POST, (long)0);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER, conn->headers);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen (void)curl_multi_remove_handle(conn->curlm, conn->curl);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen i_free(post->url);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen i_free(post);
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen conn->posting = FALSE;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen return ret;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen}
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainenint solr_connection_post(struct solr_connection *conn, const char *cmd)
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen{
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen struct solr_connection_post *post;
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen post = solr_connection_post_begin(conn);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen solr_connection_post_more(post, (const unsigned char *)cmd,
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen strlen(cmd));
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen return solr_connection_post_end(post);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen}
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainen