solr-connection.c revision 54fcc10af7fb60e495318f7e81652d05eb3e0cad
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* curl: 7.16.0 curl_multi_timeout */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_output_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* @UNSAFE */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int solr_xml_parse(struct solr_connection *conn,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (XML_Parse(conn->xml_parser, data, size, done))
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen line = XML_GetCurrentLineNumber(conn->xml_parser);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_error("fts_solr: Invalid XML input at line %d: %s",
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_input_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen (void)solr_xml_parse(conn, data, size, FALSE);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencurl_header_func(void *data, size_t element_size, size_t nmemb, void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *p;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (p[i] == ' ') {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen conn->http_failure = i_strndup(p + i, size - i);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct solr_connection *solr_connection_init(const char *url, bool debug)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (conn->curl == NULL || conn->curlm == NULL) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "fts_solr: Failed to allocate curl");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* set global curl options */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_ERRORBUFFER, conn->curl_errorbuf);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_VERBOSE, 1L);
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 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 curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER, conn->headers);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "fts_solr: Failed to allocate XML parser");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenvoid solr_connection_deinit(struct solr_connection *conn)
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainenvoid solr_connection_http_escape(struct solr_connection *conn, string_t *dest,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen const char *str)
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen encoded = curl_easy_escape(conn->curl, str, 0);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic const char *attrs_get_name(const char **attrs)
ae9365d3de0cefae6f2a5d3e9ab79bc11c37b3d5Timo Sirainensolr_lookup_xml_start(void *context, const char *name, const char **attrs)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct solr_lookup_xml_context *ctx = context;
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen /* skipping over unwanted elements */
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen /* response -> result -> doc */
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UID;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_SCORE;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_MAILBOX;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NAMESPACE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UIDVALIDITY;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void solr_lookup_add_doc(struct solr_lookup_xml_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts_solr: Query didn't return mailbox");
aa62d8779ce53900c2f09bf2ff6fa790bc9f6a89Timo Sirainen if (!ctx->callback(ctx->ns, ctx->mailbox, ctx->uidvalidity,
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct solr_lookup_xml_context *ctx = context;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ctx->state == SOLR_XML_RESPONSE_STATE_DOC)
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_NONE;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic int uint32_parse(const char *str, int len, uint32_t *value_r)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen for (i = 0; i < len; i++) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic void solr_lookup_xml_data(void *context, const char *str, int len)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct solr_lookup_xml_context *ctx = context;
e0719fca14e337eee5a0d924bc4e9d53151a7188Timo Sirainen ctx->score = strtod(t_strndup(str, len), NULL);
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);
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen new_name = ctx->ns == NULL ? i_strndup(str, len) :
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen i_strconcat(ctx->ns, t_strndup(str, len), NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uint32_parse(str, len, &ctx->uidvalidity) < 0)
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen i_error("fts_solr: received invalid uidvalidity");
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainenint solr_connection_select(struct solr_connection *conn, const char *query,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen solr_uid_map_callback_t *callback, void *context,
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen struct solr_lookup_xml_context solr_lookup_context;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen memset(&solr_lookup_context, 0, sizeof(solr_lookup_context));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen XML_SetCharacterDataHandler(conn->xml_parser, solr_lookup_xml_data);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen XML_SetUserData(conn->xml_parser, &solr_lookup_context);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen /* curl v7.16 and older don't strdup() the URL */
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen conn->last_sent_url = i_strconcat(conn->url, "select?", query, NULL);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_URL, conn->last_sent_url);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen i_error("fts_solr: Lookup failed: %s", conn->http_failure);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainensolr_connection_post_begin(struct solr_connection *conn)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_READDATA, post);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen merr = curl_multi_add_handle(conn->curlm, conn->curl);
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen i_error("fts_solr: curl_multi_add_handle() failed: %s",
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,
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_POST, (long)1);
b3bb775c6b735a7f6021dea799601fbfdb656e58Timo Sirainenvoid solr_connection_post_more(struct solr_connection_post *post,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen merr = curl_multi_perform(post->conn->curlm, &handles);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_error("fts_solr: curl_multi_perform() failed: %s",
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen if ((post->pos == post->size && post->size != 0) ||
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen /* everything sent successfully */
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen msg = curl_multi_info_read(post->conn->curlm, &n);
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen if (msg != NULL && msg->msg == CURLMSG_DONE &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* everything wasn't sent - wait. just use select,
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen since libcurl interface is easiest with it. */
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen merr = curl_multi_fdset(post->conn->curlm, &fdread, &fdwrite,
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen i_error("fts_solr: curl_multi_fdset() failed: %s",
b60baf6af900a610b2b2ddd24a46f8311acc3386Timo Sirainen merr = curl_multi_timeout(post->conn->curlm, &timeout);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_error("fts_solr: curl_multi_timeout() failed: %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout_tv);
eae1d6e75713d3d658908ac39b719992e2f8a456Timo Sirainenint solr_connection_post_end(struct solr_connection_post *post)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
41264e5dcef8335ab7ba422822b3ab518b7a327aTimo Sirainen i_error("fts_solr: Indexing failed: %s", conn->http_failure);
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 (void)curl_multi_remove_handle(conn->curlm, conn->curl);
43955c82f9f52c969c777b3da00bc170183dfdf2Timo Sirainenint solr_connection_post(struct solr_connection *conn, const char *cmd)
d61a5e0e4ff58d1aa613f0d51161e5bb0f092514Timo Sirainen solr_connection_post_more(post, (const unsigned char *)cmd,