/*
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 */