ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek libcurl tevent integration
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek Copyright (C) Red Hat, 2016
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek This program is free software; you can redistribute it and/or modify
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek it under the terms of the GNU General Public License as published by
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek the Free Software Foundation; either version 3 of the License, or
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek (at your option) any later version.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek This program is distributed in the hope that it will be useful,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek but WITHOUT ANY WARRANTY; without even the implied warranty of
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek GNU General Public License for more details.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek You should have received a copy of the GNU General Public License
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek along with this program. If not, see <http://www.gnu.org/licenses/>.
b09cd3072153663bfcce902633b5e6f9134e72e0Fabiano Fidêncio/* This limit in the same one as KCM_REPLY_MAX */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * @brief The main structure of the tcurl module.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * Use tcurl_init() to initialize it, then pass to the request.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * Should be kept opaque in the future.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * @see tcurl_init()
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* See where we set CURLMOPT_TIMERFUNCTION */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* Since we want the API to be non-blocking, all the transfers use
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * the curl's multi interface:
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * and then each transfer also uses an easy interface instance for
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * the transfer's private data
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * @brief A tevent wrapper around curl socket
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek struct tcurl_ctx *tctx; /* Backchannel to the main context */
a02a5ed51178b2cbede0396d66aed716b8898096René Genz curl_socket_t sockfd; /* curl socket is an int typedef on UNIX */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek struct tevent_fd *fde; /* tevent tracker of the fd events */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinastatic void tcurl_request_done(struct tevent_req *req,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* HTTP error does not fail the whole request, just returns the error
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * separately
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Cannot initialize global curl options [%d]\n", ret);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic void handle_curlmsg_done(CURLMsg *message)
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek DEBUG(SSSDBG_CRIT_FAILURE, "BUG: NULL handle for message %p\n", message);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek crv = curl_easy_getinfo(easy_handle, CURLINFO_EFFECTIVE_URL, &done_url);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_MINOR_FAILURE, "Cannot get CURLINFO_EFFECTIVE_URL "
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* not fatal since we need this only for debugging */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek DEBUG(SSSDBG_TRACE_FUNC, "Handled %s\n", done_url);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek crv = curl_easy_getinfo(easy_handle, CURLINFO_PRIVATE, (void *) &req);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Cannot get CURLINFO_PRIVATE [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "CURL operation failed [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* If there was no fatal error, let's read the response code
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina * and mark the request as done */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina crv = curl_easy_getinfo(easy_handle, CURLINFO_RESPONSE_CODE, &response_code);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "Cannot get response code\n");
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic void process_curl_activity(struct tcurl_ctx *tctx)
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek while ((message = curl_multi_info_read(tctx->multi_handle, &pending))) {
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic void tcurlsock_input_available(struct tevent_context *ev,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tcs = talloc_get_type(data, struct tcurl_sock);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* multi_socket_action might invalidate tcs when the transfer ends,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * so we need to store tctx separately
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* https://ec.haxx.se/libcurl-drive-multi-socket.html */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek curl_multi_socket_action(tcs->tctx->multi_handle,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * @brief Registers a curl's socket with tevent
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * Creates a private structure, registers the socket with tevent and finally
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * registers the tcurl_sock structure as a private pointer for the curl
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * socket for later
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic struct tcurl_sock *register_curl_socket(struct tcurl_ctx *tctx,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tcs->fde = tevent_add_fd(tctx->ev, tcs, sockfd, flags,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek curl_multi_assign(tctx->multi_handle, sockfd, (void *) tcs);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek/* libcurl informs the application about socket activity to wait for with
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * this callback */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tctx = talloc_get_type(userp, struct tcurl_ctx);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Activity on curl socket %d socket data %p\n", s, socketp);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* There is some activity on a socket */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* If this socket doesn't have private data, it must be a new one,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * let's start tracking it with tevent
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* If we are already tracking this socket, just set the correct
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * flags for tevent and pass the control to tevent
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tcsock = talloc_get_type(socketp, struct tcurl_sock);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "BUG: No private data for socket %d\n", s);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* This socket is being closed by curl, so we need to.. */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tcsock = talloc_get_type(socketp, struct tcurl_sock);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "BUG: Trying to remove an untracked socket %d\n", s);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* ..stop tracking the socket with the multi handle.. */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek curl_multi_assign(tctx->multi_handle, s, NULL);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* ..and stop tracking the fd with tevent */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic void check_curl_timeouts(struct tcurl_ctx *tctx)
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Still tracking %d outstanding requests\n", running_handles);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* https://ec.haxx.se/libcurl-drive-multi-socket.html */
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic void check_fd_activity(struct tevent_context *ev,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek struct tcurl_ctx *tctx = talloc_get_type(private_data, struct tcurl_ctx);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek struct tcurl_ctx *tctx = talloc_get_type(userp, struct tcurl_ctx);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek DEBUG(SSSDBG_TRACE_INTERNAL, "timeout_ms: %ld\n", timeout_ms);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* man curlmopt_timerfunction(3) says:
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * A timeout_ms value of -1 means you should delete your timer.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tv = tevent_timeval_current_ofs(0, timeout_ms * 1000);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* There is only one timer per multi handle, so it makes sense to cancel
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * the previous one.
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * From https://ec.haxx.se/libcurl-drive-multi-socket.html:
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * There is only one timeout for the application to handle for the
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * entire multi handle, no matter how many individual easy handles
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * that have been added or transfers that are in progress. The timer
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * callback will be updated with the current nearest-in-time period to
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek tctx->process_timer = tevent_add_timer(tctx->ev, tctx, tv,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstatic int tcurl_ctx_destroy(struct tcurl_ctx *ctx)
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozekstruct tcurl_ctx *tcurl_init(TALLOC_CTX *mem_ctx,
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* Per the manpage it is safe to call the initialization multiple
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * times, as long as this is done before any other curl calls to
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * make sure we don't mangle the global curl environment
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek talloc_set_destructor(tctx, tcurl_ctx_destroy);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Cannot set CURLMOPT_SOCKETDATA [%d]: %s\n",
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * When there is some activity on a socket associated with the multi
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * handle, then the handle_socket() function will be called with the
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * global context as private data
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Cannot set CURLMOPT_SOCKETFUNCTION [%d]: %s\n",
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* When integrated in a mainloop, the curl multi interface must
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * kick off the communication in another eventloop tick. Similar
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * to the handle_socet function, the tcurl context is passed in
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * as private data
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek CURLMOPT_TIMERFUNCTION, schedule_fd_processing);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Cannot set CURLMOPT_TIMERFUNCTION [%d]: %s\n",
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek cmret = curl_multi_setopt(tctx->multi_handle, CURLMOPT_TIMERDATA, tctx);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek "Cannot set CURLMOPT_TIMERDATA [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina#define tcurl_set_option(tcurl_req, option, value) \
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina __curl_code = curl_easy_setopt((tcurl_req)->curl_easy_handle, \
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_OP_FAILURE, "Failed to set CURL option %s [%d]: %s\n", \
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina #option, __curl_code, curl_easy_strerror(__curl_code)); \
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina outbuf = talloc_get_type(userdata, struct sss_iobuf);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_TRACE_INTERNAL, "---> begin libcurl data\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_TRACE_INTERNAL, "<--- end libcurl data\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = sss_iobuf_write_len(outbuf, (uint8_t *)ptr, realsize);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Failed to write data to buffer [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* zero signifies an EOF */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina inbuf = talloc_get_type(userdata, struct sss_iobuf);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = sss_iobuf_read(inbuf, size * nmemb, ptr, &readbytes);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* Associated tcurl context if this request is in progress. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina req = tevent_req_create(mem_ctx, &state, struct tcurl_request_state);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Unable to create tevent request!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "Sending TCURL request for %s, at socket %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req->url == NULL ? "<none>" : tcurl_req->url,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req->socket == NULL ? "<none>" : tcurl_req->socket);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina state->tcurl_req = talloc_steal(state, tcurl_req);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina state->response = sss_iobuf_init_empty(state, TCURL_IOBUF_CHUNK, TCURL_IOBUF_MAX);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_PRIVATE, req);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_TIMEOUT, timeout);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEFUNCTION, tcurl_write_data);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_WRITEDATA, state->response);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_READFUNCTION, tcurl_read_data);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_READDATA, tcurl_req->body);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina curl_code = curl_multi_add_handle(tcurl_ctx->multi_handle,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinastatic void tcurl_request_done(struct tevent_req *req,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_TRACE_FUNC, "TCURL request finished [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* To handle case where we fail to obtain request from private data. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_MINOR_FAILURE, "No tevent request provided!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina state = tevent_req_data(req, struct tcurl_request_state);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina curl_multi_remove_handle(state->tcurl_req->tcurl_ctx->multi_handle,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* This request is no longer associated with tcurl context. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinaerrno_t tcurl_request_recv(TALLOC_CTX *mem_ctx,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina state = tevent_req_data(req, struct tcurl_request_state);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina *_response = talloc_steal(mem_ctx, state->response);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinastatic struct curl_slist *
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinatcurl_add_header(struct curl_slist *slist, const char *header)
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Cannot add header %s\n", header);
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek /* Add a dummy header to suppress libcurl adding Expect 100-continue which
ca90f2102a43a3d49a2ef26610d7b4ff3062a823Jakub Hrozek * was causing libcurl to always wait for the internal timeout when sending
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina * a PUT/POST request because secrets responder does not implement this.
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinatcurl_request_destructor(struct tcurl_request *tcurl_req)
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_MINOR_FAILURE, "Terminating TCURL request...\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina curl_multi_remove_handle(tcurl_req->tcurl_ctx->multi_handle,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina curl_easy_cleanup(tcurl_req->curl_easy_handle);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char *url,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char **headers,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req = talloc_zero(mem_ctx, struct tcurl_request);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "URL cannot be NULL!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* Setup a curl easy handle. This handle contains state for the request
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina * and is later associated with curl multi handle which performs
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina * asynchronous processing. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req->curl_easy_handle = curl_easy_init();
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Unable to initialize curl easy handle!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req->url = talloc_strdup(tcurl_req, url);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req->socket = talloc_strdup(tcurl_req, socket_path);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_construct_headers(headers, &tcurl_req->headers);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "Unable to construct headers [%d]: %s\n",
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina talloc_set_destructor(tcurl_req, tcurl_request_destructor);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_URL, url);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_UNIX_SOCKET_PATH, socket_path);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* Curl will tell the underlying protocol about incoming data length.
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina * In case of HTTP it will add a sane Content-Length header. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_INFILESIZE_LARGE,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinastruct tcurl_request *tcurl_http(TALLOC_CTX *mem_ctx,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char *url,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char **headers,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req = tcurl_request_create(mem_ctx, socket_path, url, headers, body);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* Set HTTP specific options. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPHEADER, tcurl_req->headers);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* Nothing to do here. GET is default. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_UPLOAD, 1L);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "POST");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_CUSTOMREQUEST, "DELETE");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinastruct tevent_req *tcurl_http_send(TALLOC_CTX *mem_ctx,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char *url,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char **headers,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina tcurl_req = tcurl_http(mem_ctx, method, socket_path, url, headers, body);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina req = tcurl_request_send(mem_ctx, ev, tcurl_ctx, tcurl_req, timeout);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina return tcurl_request_recv(mem_ctx, req, _response, _http_code);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinaerrno_t tcurl_req_enable_rawoutput(struct tcurl_request *tcurl_req)
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina return tcurl_set_option(tcurl_req, CURLOPT_HEADER, 1L);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinaerrno_t tcurl_req_verify_peer(struct tcurl_request *tcurl_req,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYPEER, peer);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_SSL_VERIFYHOST, host);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_CAPATH, capath);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_CAINFO, cacert);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březinaerrno_t tcurl_req_set_client_cert(struct tcurl_request *tcurl_req,
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina const char *key)
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina DEBUG(SSSDBG_CRIT_FAILURE, "You must specify client certificate!\n");
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_SSLCERT, cert);
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina /* If client's private key is in separate file. */
300b9e9217ee1ed8d845ed2370c5ccf5c87afb36Pavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_SSLKEY, key);
c2ea75da72b426d98ba489039e220d417bfb4c2aPavel Březinaerrno_t tcurl_req_http_basic_auth(struct tcurl_request *tcurl_req,
c2ea75da72b426d98ba489039e220d417bfb4c2aPavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
c2ea75da72b426d98ba489039e220d417bfb4c2aPavel Březina ret = tcurl_set_option(tcurl_req, CURLOPT_USERNAME, username);