28#include <microhttpd.h>
33#include "../util/benchmark.h"
48#define CURL_STRERROR(type, function, code) \
50 "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
54 curl_easy_strerror (code));
59#define JSON_WARN(error) \
60 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
61 "JSON parsing failed at %s:%u: %s (%s)\n", \
216 const char *userpass)
219 if (NULL != userpass)
226 const char *certtype,
227 const char *certfile,
235 if (NULL != certtype)
237 if (NULL != certfile)
257 "Curl was not initialised properly\n");
260 if (NULL == (
multi = curl_multi_init ()))
263 "Failed to create a Curl multi handle\n");
266 if (NULL == (
share = curl_share_init ()))
269 "Failed to create a Curl share handle\n");
283 const char *header_name)
285 ctx->async_scope_id_header = header_name;
292 if (strlen (scope_id) >= 64)
294 for (
size_t i = 0; i < strlen (scope_id); i++)
295 if (! (isalnum (scope_id[i]) || (scope_id[i] ==
'-')))
324 if (0 ==
size * nitems)
329 msize =
size * nitems;
336 db->buf_size + msize);
339 db->buf_size += msize;
351static struct curl_slist *
353 const struct curl_slist *job_headers)
355 struct curl_slist *all_headers = NULL;
357 for (
const struct curl_slist *curr = job_headers;
362 (all_headers = curl_slist_append (all_headers,
366 for (
const struct curl_slist *curr =
ctx->common_headers;
371 (all_headers = curl_slist_append (all_headers,
375 if (NULL !=
ctx->async_scope_id_header)
409 struct curl_slist *all_headers)
414 curl_easy_setopt (eh,
419 curl_slist_free_all (all_headers);
420 curl_easy_cleanup (eh);
425 job->job_headers = all_headers;
428 curl_easy_setopt (eh,
432 curl_easy_setopt (eh,
433 CURLOPT_WRITEFUNCTION,
436 curl_easy_setopt (eh,
440 curl_easy_setopt (eh,
446 curl_easy_cleanup (eh);
450 curl_multi_add_handle (
ctx->multi,
455 curl_easy_cleanup (eh);
458 job->easy_handle = eh;
469 const struct curl_slist *extra_headers)
471 struct curl_slist *all_headers =
job->job_headers;
473 for (
const struct curl_slist *curr = extra_headers;
478 (all_headers = curl_slist_append (all_headers,
481 job->job_headers = all_headers;
493 struct curl_slist *all_headers;
503 job->jcc_raw_cls = jcc_cls;
517 struct curl_slist *all_headers;
520 if ( (NULL !=
ctx->userpass) &&
521 (0 != curl_easy_setopt (eh,
525 if ( (NULL !=
ctx->certfile) &&
526 (0 != curl_easy_setopt (eh,
530 if ( (NULL !=
ctx->certtype) &&
531 (0 != curl_easy_setopt (eh,
535 if ( (NULL !=
ctx->keyfile) &&
536 (0 != curl_easy_setopt (eh,
540 if ( (NULL !=
ctx->keypass) &&
541 (0 != curl_easy_setopt (eh,
554 job->jcc_cls = jcc_cls;
567 struct curl_slist *job_headers = NULL;
570 curl_slist_append (NULL,
571 "Content-Type: application/json")
578 curl_slist_free_all (job_headers);
606 curl_multi_remove_handle (
ctx->multi,
608 curl_easy_cleanup (
job->easy_handle);
610 curl_slist_free_all (
job->job_headers);
628 if (0 == strcasecmp (ct,
640 if (semi - ct != strlen (
"application/json"))
642 if (0 == strncasecmp (ct,
644 strlen (
"application/json")))
660 "Downloaded body: %.*s\n",
665 curl_easy_getinfo (eh,
666 CURLINFO_RESPONSE_CODE,
673 if (MHD_HTTP_NO_CONTENT == *response_code)
676 curl_easy_getinfo (eh,
677 CURLINFO_CONTENT_TYPE,
684 if (0 !=
db->buf_size)
689 curl_easy_getinfo (eh,
690 CURLINFO_EFFECTIVE_URL,
692 url =
"<unknown URL>";
694 "Request to `%s' was expected to return a body of type `application/json', got `%s'\n",
700 if (0 == *response_code)
705 curl_easy_getinfo (eh,
706 CURLINFO_EFFECTIVE_URL,
708 url =
"<unknown URL>";
710 "Failed to download response from `%s': \n",
719 json = json_loadb (
db->buf,
721 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
728 "Failed to parse JSON response: %s\n",
743 ctx->common_headers = curl_slist_append (
ctx->common_headers,
745 if (NULL ==
ctx->common_headers)
761 (void) curl_multi_perform (
ctx->multi,
763 while (NULL != (cmsg = curl_multi_info_read (
ctx->multi,
774 curl_easy_getinfo (cmsg->easy_handle,
780 if (NULL !=
job->jcc_raw)
784 curl_easy_getinfo (
job->easy_handle,
785 CURLINFO_RESPONSE_CODE,
787 job->jcc_raw (
job->jcc_raw_cls,
804 const char *url = NULL;
806 if (CURLE_UNKNOWN_OPTION ==
807 curl_easy_getinfo (
job->easy_handle,
808 CURLINFO_EFFECTIVE_URL,
812 "HTTP request for `%s' finished with %u after %s\n",
814 (
unsigned int) response_code,
836 fd_set *write_fd_set,
837 fd_set *except_fd_set,
846 curl_multi_fdset (
ctx->multi,
854 curl_multi_timeout (
ctx->multi,
859 if ((to < *
timeout) && (-1 != to))
861 if ((-1 == (*
timeout)) && (NULL !=
ctx->jobs_head))
871 curl_share_cleanup (
ctx->share);
872 curl_multi_cleanup (
ctx->multi);
873 curl_slist_free_all (
ctx->common_headers);
893 if (CURLE_OK != (
ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
913 curl_global_cleanup ();
void GNUNET_CURL_constructor__(void)
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
#define JSON_WARN(error)
Print JSON parsing related error information.
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
Create a job.
static size_t download_cb(char *bufptr, size_t size, size_t nitems, void *cls)
Callback used when downloading the reply to an HTTP request.
static int curl_fail
Failsafe flag.
static struct curl_slist * setup_job_headers(struct GNUNET_CURL_Context *ctx, const struct curl_slist *job_headers)
Create the HTTP headers for the request.
void GNUNET_CURL_destructor__(void)
void * GNUNET_CURL_download_get_result_(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
void __attribute__((constructor))
Initial global setup logic, specifically runs the Curl setup.
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
static int ret
Final status code.
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
static CURLM * multi
Current multi-CURL handle.
static struct MHD_Response * response
Our canonical response.
static struct GNUNET_FS_Handle * ctx
static char * rp
Relying party.
static struct GNUNET_FS_DirectoryBuilder * db
static struct GNUNET_TIME_Relative duration
Option '-d': duration of the mapping.
library to make it easy to download JSON replies over HTTP
void GNUNET_CURL_set_tlscert(struct GNUNET_CURL_Context *ctx, const char *certtype, const char *certfile, const char *keyfile, const char *keypass)
Force use of the provided TLS client certificate for client authentication for all operations perform...
void(* GNUNET_CURL_RawJobCompletionCallback)(void *cls, long response_code, const void *body, size_t body_size)
Function to call upon completion of a raw job.
void(* GNUNET_CURL_JobCompletionCallback)(void *cls, long response_code, const void *response)
Function to call upon completion of a job.
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)
Schedule a CURL request to be executed and call the given jcc upon its completion.
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 jcc upon its completion.
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)
Obtain the information for a select() call to wait until GNUNET_CURL_perform() is ready again.
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
void GNUNET_CURL_extend_headers(struct GNUNET_CURL_Job *job, const struct curl_slist *extra_headers)
Add extra_headers to the HTTP headers for job.
void GNUNET_CURL_perform2(struct GNUNET_CURL_Context *ctx, GNUNET_CURL_RawParser rp, GNUNET_CURL_ResponseCleaner rc)
Run the main event loop for the HTTP interaction.
void GNUNET_CURL_job_cancel(struct GNUNET_CURL_Job *job)
Cancel a job.
enum GNUNET_GenericReturnValue GNUNET_CURL_is_valid_scope_id(const char *scope_id)
Return GNUNET_YES if given a valid scope ID and GNUNET_NO otherwise.
void GNUNET_CURL_perform(struct GNUNET_CURL_Context *ctx)
Run the main event loop for the CURL interaction.
void GNUNET_CURL_set_userpass(struct GNUNET_CURL_Context *ctx, const char *userpass)
Force use of the provided username and password for client authentication for all operations performe...
void *(* GNUNET_CURL_RawParser)(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Parses the raw response we got from the Web server.
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)
Schedule a CURL request to be executed and call the given jcc upon its completion.
enum GNUNET_GenericReturnValue GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
void(* GNUNET_CURL_RescheduleCallback)(void *cls)
Function called by the context to ask for the event loop to be rescheduled, that is the application s...
void GNUNET_CURL_enable_async_scope_header(struct GNUNET_CURL_Context *ctx, const char *header_name)
Enable sending the async scope ID as a header.
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 jcc upon its completion.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_log(kind,...)
int have_scope
GNUNET_YES unless this saved scope is the unnamed root scope.
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
struct GNUNET_AsyncScopeId scope_id
Saved scope.
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
#define GNUNET_free(ptr)
Wrapper around free.
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
const char * GNUNET_TIME_relative2s(struct GNUNET_TIME_Relative delta, bool do_round)
Give relative time in human-readable fancy format.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
static unsigned int size
Size of the "table".
Identifier for an asynchronous execution context.
Saved async scope identifier or root scope.
char * userpass
USERNAME:PASSWORD to use for client-authentication with all requests of this context,...
char * keypass
Passphrase to decrypt keyfile, or NULL.
void * cb_cls
Closure for cb.
char * certtype
Type of the TLS client certificate used, or NULL.
char * keyfile
File with the private key to authenticate the TLS client, or NULL.
struct curl_slist * common_headers
Headers common for all requests in the context.
CURLSH * share
Curl share handle.
const char * async_scope_id_header
If non-NULL, the async scope ID is sent in a request header of this name.
CURLM * multi
Curl multi handle.
GNUNET_CURL_RescheduleCallback cb
Function we need to call whenever the event loop's socket set changed.
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
char * certfile
File with the TLS client certificate, or NULL.
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser.
void * buf
Download buffer.
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
struct GNUNET_CURL_Job * prev
We keep jobs in a DLL.
CURL * easy_handle
Easy handle of the job.
struct curl_slist * job_headers
Headers used for this job, the list needs to be freed after the job has finished.
void * jcc_raw_cls
Closure for jcc_raw.
struct GNUNET_CURL_Context * ctx
Context this job runs in.
struct GNUNET_TIME_Absolute start_time
When did we start the job?
GNUNET_CURL_JobCompletionCallback jcc
Function to call upon completion.
void * jcc_cls
Closure for jcc.
struct GNUNET_CURL_DownloadBuffer db
Buffer for response received from CURL.
struct GNUNET_CURL_Job * next
We keep jobs in a DLL.
GNUNET_CURL_RawJobCompletionCallback jcc_raw
Function to call upon completion.
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.