/* This file is part of GNUnet Copyright (C) 2014, 2015, 2016 GNUnet e.V. GNUnet is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . SPDX-License-Identifier: AGPL3.0-or-later */ /** * @file src/include/gnunet_curl_lib.h * @brief library to make it easy to download JSON replies over HTTP * @author Sree Harsha Totakura * @author Christian Grothoff * * @defgroup curl CURL integration library * Download JSON using libcurl. * @{ */ #ifndef GNUNET_CURL_LIB_H #define GNUNET_CURL_LIB_H #if HAVE_LIBCURL #include #elif HAVE_LIBGNURL #include #else #error "needs curl or gnurl" #endif #include "gnunet_util_lib.h" /** * Function called by the context to ask for the event loop to be * rescheduled, that is the application should call * #GNUNET_CURL_get_select_info() as the set of sockets we care about * just changed. * * @param cls closure */ typedef void (*GNUNET_CURL_RescheduleCallback)(void *cls); /** * @brief Buffer data structure we use to buffer the HTTP download * before giving it to the JSON parser. */ struct GNUNET_CURL_DownloadBuffer { /** * Download buffer */ void *buf; /** * The size of the download buffer */ size_t buf_size; /** * Error code (based on libc errno) if we failed to download * (i.e. response too large). */ int eno; }; /** * Parses the raw response we got from the Web server. * * @param db the raw data * @param eh handle * @param response_code HTTP response code * @return the parsed object */ typedef void * (*GNUNET_CURL_RawParser) (struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code); /** * Deallocate the response. * * @param response object to clean */ typedef void (*GNUNET_CURL_ResponseCleaner) (void *response); /** * Initialise this library. This function should be called before using any of * the following functions. * * @param cb function to call when rescheduling is required * @param cb_cls closure for @a cb * @return library context */ struct GNUNET_CURL_Context * GNUNET_CURL_init (GNUNET_CURL_RescheduleCallback cb, void *cb_cls); /** * Obtain the information for a select() call to wait until * #GNUNET_CURL_perform() is ready again. * * Basically, a client should use this API to prepare for select(), * then block on select(), then call #GNUNET_CURL_perform() and then * start again until the work with the context is done. * * This function will NOT zero out the sets and assumes that @a max_fd * and @a timeout are already set to minimal applicable values. It is * safe to give this API FD-sets and @a max_fd and @a timeout that are * already initialized to some other descriptors that need to go into * the select() call. * * @param ctx context to get the event loop information for * @param read_fd_set will be set for any pending read operations * @param write_fd_set will be set for any pending write operations * @param except_fd_set is here because curl_multi_fdset() has this argument * @param max_fd set to the highest FD included in any set; * if the existing sets have no FDs in it, the initial * value should be "-1". (Note that `max_fd + 1` will need * to be passed to select().) * @param timeout set to the timeout in milliseconds (!); -1 means * no timeout (NULL, blocking forever is OK), 0 means to * proceed immediately with #GNUNET_CURL_perform(). */ void GNUNET_CURL_get_select_info (struct GNUNET_CURL_Context *ctx, fd_set *read_fd_set, fd_set *write_fd_set, fd_set *except_fd_set, int *max_fd, long *timeout); /** * Add custom request header. * * @param ctx cURL context. * @param header header string; will be given to the context AS IS. * @return #GNUNET_OK if no errors occurred, #GNUNET_SYSERR otherwise. */ int GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header); /** * Run the main event loop for the CURL interaction. * * @param ctx the library context */ void GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx); /** * Run the main event loop for the HTTP interaction. * * @param ctx the library context * @param rp parses the raw response returned from * the Web server. * @param rc cleans/frees the response */ void GNUNET_CURL_perform2 (struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, GNUNET_CURL_ResponseCleaner rc); /** * Cleanup library initialisation resources. This function should be called * after using this library to cleanup the resources occupied during library's * initialisation. * * @param ctx the library context */ void GNUNET_CURL_fini (struct GNUNET_CURL_Context *ctx); /** * Entry in the context's job queue. */ struct GNUNET_CURL_Job; /** * Function to call upon completion of a job. * * @param cls closure * @param response_code HTTP response code from server, 0 on hard error * @param response in JSON, NULL if response was not in JSON format */ typedef void (*GNUNET_CURL_JobCompletionCallback)(void *cls, long response_code, const void *response); /** * Function to call upon completion of a raw job. * * @param cls closure * @param response_code HTTP response code from server, 0 on hard error * @param body http body of the response * @param body_size number of bytes in @a body */ typedef void (*GNUNET_CURL_RawJobCompletionCallback)(void *cls, long response_code, const void *body, size_t body_size); /** * Schedule a CURL request to be executed and call the given @a jcc * upon its completion. Note that the context will make use of the * CURLOPT_PRIVATE facility of the CURL @a eh. * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc * @return NULL on error (in this case, @eh is still released!) */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add (struct GNUNET_CURL_Context *ctx, CURL *eh, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls); /** * Schedule a CURL request to be executed and call the given @a jcc * upon its completion. Note that the context will make use of the * CURLOPT_PRIVATE facility of the CURL @a eh. * * This function modifies the CURL handle to add the * "Content-Type: application/json" header. * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc * @return NULL on error (in this case, @eh is still released!) */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add_with_ct_json (struct GNUNET_CURL_Context *ctx, CURL *eh, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls); /** * Force use of the provided username and password * for client authentication for all operations performed * with @a ctx. * * @param ctx context to set authentication data for * @param userpass string with "$USERNAME:$PASSWORD" */ void GNUNET_CURL_set_userpass (struct GNUNET_CURL_Context *ctx, const char *userpass); /** * Force use of the provided TLS client certificate for client authentication * for all operations performed with @a ctx. * * Note that if the provided information is incorrect, * the earliest operation that could fail is * #GNUNET_CURL_job_add() or #GNUNET_CURL_job_add2()! * * @param ctx context to set authentication data for * @param certtype type of the certificate * @param certfile file with the certificate * @param keyfile file with the private key * @param keypass passphrase to decrypt @a keyfile (or NULL) */ void GNUNET_CURL_set_tlscert (struct GNUNET_CURL_Context *ctx, const char *certtype, const char *certfile, const char *keyfile, const char *keypass); /** * Schedule a CURL request to be executed and call the given @a jcc upon its * completion. Note that the context will make use of the CURLOPT_PRIVATE * facility of the CURL @a eh. * * This function modifies the CURL handle to add the * "Content-Type: application/json" header if @a add_json is set. * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up * @param job_headers extra headers to add for this request * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc * @return NULL on error (in this case, @eh is still released!) */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add2 (struct GNUNET_CURL_Context *ctx, CURL *eh, const struct curl_slist *job_headers, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls); /** * Schedule a CURL request to be executed and call the given @a jcc * upon its completion. Note that the context will make use of the * CURLOPT_PRIVATE facility of the CURL @a eh. Used to download * resources that are NOT in JSON. The raw body will be returned. * * @param ctx context to execute the job in * @param eh curl easy handle for the request, will * be executed AND cleaned up * @param job_headers extra headers to add for this request * @param max_reply_size largest acceptable response body * @param jcc callback to invoke upon completion * @param jcc_cls closure for @a jcc * @return NULL on error (in this case, @eh is still released!) */ struct GNUNET_CURL_Job * GNUNET_CURL_job_add_raw (struct GNUNET_CURL_Context *ctx, CURL *eh, const struct curl_slist *job_headers, GNUNET_CURL_RawJobCompletionCallback jcc, void *jcc_cls); /** * Add @a extra_headers to the HTTP headers for @a job. * * @param[in,out] job the job to modify * @param extra_headers headers to append */ void GNUNET_CURL_extend_headers (struct GNUNET_CURL_Job *job, const struct curl_slist *extra_headers); /** * Cancel a job. Must only be called before the job completion * callback is called for the respective job. * * @param job job to cancel */ void GNUNET_CURL_job_cancel (struct GNUNET_CURL_Job *job); /* ******* GNUnet SCHEDULER integration ************ */ /** * Closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext; /** * Initialize reschedule context. * * @param ctx context to manage * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext * GNUNET_CURL_gnunet_rc_create (struct GNUNET_CURL_Context *ctx); /** * Initialize reschedule context; with custom response parser * * @param ctx context to manage * @return closure for #GNUNET_CURL_gnunet_scheduler_reschedule(). */ struct GNUNET_CURL_RescheduleContext * GNUNET_CURL_gnunet_rc_create_with_parser (struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, GNUNET_CURL_ResponseCleaner rc); /** * Destroy reschedule context. * * @param rc context to destroy */ void GNUNET_CURL_gnunet_rc_destroy (struct GNUNET_CURL_RescheduleContext *rc); /** * Implementation of the #GNUNET_CURL_RescheduleCallback for GNUnet's * scheduler. Will run the CURL context using GNUnet's scheduler. * Note that you MUST immediately destroy the reschedule context after * calling #GNUNET_CURL_fini(). * * @param cls must point to a `struct GNUNET_CURL_RescheduleContext *` * (pointer to a pointer!) */ void GNUNET_CURL_gnunet_scheduler_reschedule (void *cls); /** * Enable sending the async scope ID as a header. * * @param ctx the context to enable this for * @param header_name name of the header to send. */ void GNUNET_CURL_enable_async_scope_header (struct GNUNET_CURL_Context *ctx, const char *header_name); /** * Return #GNUNET_YES if given a valid scope ID and * #GNUNET_NO otherwise. See * #GNUNET_CURL_enable_async_scope_header() for the * code that generates such a @a scope_id in an HTTP * header. * * @returns #GNUNET_YES iff given a valid scope ID */ int GNUNET_CURL_is_valid_scope_id (const char *scope_id); #endif /** @} */ /* end of group */ /* end of gnunet_curl_lib.h */