solr-connection.c revision acc4e0a41f1c8ef0559a19c280afc1b97b9e0818
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch/* curl: 7.16.0 curl_multi_timeout */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const unsigned char *data;
7384b4e78eaab44693c985192276e31322155e32Stephan Boschcurl_output_func(void *data, size_t element_size, size_t nmemb, void *context)
6d573191bea1a64d6046be070487a5705a2d0204Stephan Bosch /* @UNSAFE */
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic int solr_xml_parse(struct solr_connection *conn,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (XML_Parse(conn->xml_parser, data, size, done))
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen line = XML_GetCurrentLineNumber(conn->xml_parser);
fe681e6db72f30bd754b622005bbe298e5ca775aTimo Sirainen i_error("fts_solr: Invalid XML input at line %d: %s",
fb1be3de0159d6a10e916ad992e2bc53be64c6d5Timo Sirainencurl_input_func(void *data, size_t element_size, size_t nmemb, void *context)
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainen (void)solr_xml_parse(conn, data, size, FALSE);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschcurl_header_func(void *data, size_t element_size, size_t nmemb, void *context)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const unsigned char *p;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (p[i] == ' ') {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch conn->http_failure = i_strndup(p + i, size - i);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstruct solr_connection *solr_connection_init(const char *url, bool debug)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (conn->curl == NULL || conn->curlm == NULL) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch "fts_solr: Failed to allocate curl");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch /* set global curl options */
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_ERRORBUFFER, conn->curl_errorbuf);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_VERBOSE, 1L);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_NOPROGRESS, 1L);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_NOSIGNAL, 1L);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_READFUNCTION, curl_output_func);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_WRITEFUNCTION, curl_input_func);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_WRITEDATA, conn);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_HEADERFUNCTION, curl_header_func);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_HEADERDATA, conn);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch conn->headers = curl_slist_append(NULL, "Content-Type: text/xml");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch conn->headers_post = curl_slist_append(NULL, "Content-Type: text/xml");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch conn->headers_post = curl_slist_append(conn->headers_post,
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch "Transfer-Encoding: chunked");
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch conn->headers_post = curl_slist_append(conn->headers_post,
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER, conn->headers);
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen "fts_solr: Failed to allocate XML parser");
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid solr_connection_deinit(struct solr_connection *conn)
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid solr_connection_quote_str(struct solr_connection *conn, string_t *dest,
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainen const char *str)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch encoded = curl_easy_escape(conn->curl, str_escape(str), 0);
4521d35c263add6af3f1ae55b3760291767ce50cTimo Sirainenstatic const char *attrs_get_name(const char **attrs)
7384b4e78eaab44693c985192276e31322155e32Stephan Boschsolr_lookup_xml_start(void *context, const char *name, const char **attrs)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct solr_lookup_xml_context *ctx = context;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch /* skipping over unwanted elements */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* response -> result -> doc */
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_UID;
791fb70b3255a11a91ce0c2dc3ae1460d4cf8459Timo Sirainen ctx->content_state = SOLR_XML_CONTENT_STATE_SCORE;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch ctx->content_state = SOLR_XML_CONTENT_STATE_MAILBOX;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch ctx->content_state = SOLR_XML_CONTENT_STATE_UIDVALIDITY;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic void solr_lookup_add_doc(struct solr_lookup_xml_context *ctx)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch i_error("fts_solr: Query didn't return mailbox");
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (!ctx->callback(ctx->mailbox, ctx->uidvalidity,
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic void solr_lookup_xml_end(void *context, const char *name ATTR_UNUSED)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct solr_lookup_xml_context *ctx = context;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch if (ctx->state == SOLR_XML_RESPONSE_STATE_DOC)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch ctx->content_state = SOLR_XML_CONTENT_STATE_NONE;
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic int uint32_parse(const char *str, int len, uint32_t *value_r)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch for (i = 0; i < len; i++) {
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Boschstatic void solr_lookup_xml_data(void *context, const char *str, int len)
eb325a5a90c1d2655e74972bde0de6a699d2c864Stephan Bosch struct solr_lookup_xml_context *ctx = context;
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen ctx->score = strtod(t_strndup(str, len), NULL);
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen /* this may be called multiple times, for example if input
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen contains '&' characters */
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen new_name = ctx->mailbox == NULL ? i_strndup(str, len) :
069b28a2ef54072a221fe4ac67aaeb4e83fee6c1Timo Sirainen i_strconcat(ctx->mailbox, t_strndup(str, len), NULL);
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch if (uint32_parse(str, len, &ctx->uidvalidity) < 0)
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch i_error("fts_solr: received invalid uidvalidity");
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Boschint solr_connection_select(struct solr_connection *conn, const char *query,
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch solr_uid_map_callback_t *callback, void *context,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct solr_lookup_xml_context solr_lookup_context;
667de5cf294d833b3d47dd455bacff4fd68dd146Timo Sirainen memset(&solr_lookup_context, 0, sizeof(solr_lookup_context));
50d1446e71cfbdc5b6d7bafcf91b7bff453989d3Stephan Bosch XML_SetCharacterDataHandler(conn->xml_parser, solr_lookup_xml_data);
50d1446e71cfbdc5b6d7bafcf91b7bff453989d3Stephan Bosch XML_SetUserData(conn->xml_parser, &solr_lookup_context);
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_URL, str_c(str));
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch i_error("fts_solr: Lookup failed: %s", conn->http_failure);
65c0e43da8cfc730eeb4634f8aa384081bbfa4e7Timo Sirainensolr_connection_post_begin(struct solr_connection *conn)
a4e186e3ef267fc7a6b592788067c8c9c87d0785Stephan Bosch curl_easy_setopt(conn->curl, CURLOPT_READDATA, post);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch merr = curl_multi_add_handle(conn->curlm, conn->curl);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_error("fts_solr: curl_multi_add_handle() failed: %s",
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch curl_easy_setopt(conn->curl, CURLOPT_URL, str_c(str));
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch curl_easy_setopt(conn->curl, CURLOPT_POST, (long)1);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschvoid solr_connection_post_more(struct solr_connection_post *post,
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch merr = curl_multi_perform(post->conn->curlm, &handles);
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch i_error("fts_solr: curl_multi_perform() failed: %s",
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen if ((post->pos == post->size && post->size != 0) ||
b99130e4cf4af4e6b103b949456222f3a2dff424Timo Sirainen /* everything sent successfully */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch msg = curl_multi_info_read(post->conn->curlm, &n);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (msg != NULL && msg->msg == CURLMSG_DONE &&
dd61a7356c4e00d733fd6cd99b29d979b9eb26dfTimo Sirainen /* everything wasn't sent - wait. just use select,
dd61a7356c4e00d733fd6cd99b29d979b9eb26dfTimo Sirainen since libcurl interface is easiest with it. */
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch merr = curl_multi_fdset(post->conn->curlm, &fdread, &fdwrite,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_error("fts_solr: curl_multi_fdset() failed: %s",
87c121a4c05b9cee46f1f757ec6999d441519abfStephan Bosch merr = curl_multi_timeout(post->conn->curlm, &timeout);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch i_error("fts_solr: curl_multi_timeout() failed: %s",
99feb6521535a7dc59d8dda89981ceac084b3e88Timo Sirainen ret = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout_tv);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschint solr_connection_post_end(struct solr_connection_post *post)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch curl_easy_getinfo(conn->curl, CURLINFO_RESPONSE_CODE, &httpret);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen i_error("fts_solr: Indexing failed: %s", conn->http_failure);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_READDATA, NULL);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_POST, (long)0);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen curl_easy_setopt(conn->curl, CURLOPT_HTTPHEADER, conn->headers);
ccd968b44a40b9c2cf6278fabfa2a80cc5d9e46bTimo Sirainen (void)curl_multi_remove_handle(conn->curlm, conn->curl);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschint solr_connection_post(struct solr_connection *conn, const char *cmd)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch solr_connection_post_more(post, (const unsigned char *)cmd,