28 #include <microhttpd.h>
32 #include "../util/benchmark.h"
43 #define CURL_STRERROR(type, function, code) \
45 "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
49 curl_easy_strerror (code));
54 #define JSON_WARN(error) \
55 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
56 "JSON parsing failed at %s:%u: %s (%s)\n", \
206 const char *userpass)
209 if (NULL != userpass)
216 const char *certtype,
217 const char *certfile,
225 if (NULL != certtype)
227 if (NULL != certfile)
247 "Curl was not initialised properly\n");
250 if (NULL == (
multi = curl_multi_init ()))
253 "Failed to create a Curl multi handle\n");
256 if (NULL == (
share = curl_share_init ()))
259 "Failed to create a Curl share handle\n");
273 const char *header_name)
275 ctx->async_scope_id_header = header_name;
282 if (strlen (scope_id) >= 64)
284 for (
size_t i = 0; i < strlen (scope_id); i++)
285 if (! (isalnum (scope_id[i]) || (scope_id[i] ==
'-')))
314 if (0 ==
size * nitems)
319 msize =
size * nitems;
326 db->buf_size + msize);
329 db->buf_size += msize;
341 static struct curl_slist *
343 const struct curl_slist *job_headers)
345 struct curl_slist *all_headers = NULL;
347 for (
const struct curl_slist *curr = job_headers;
352 (all_headers = curl_slist_append (all_headers,
356 for (
const struct curl_slist *curr =
ctx->common_headers;
361 (all_headers = curl_slist_append (all_headers,
365 if (NULL !=
ctx->async_scope_id_header)
399 struct curl_slist *all_headers)
404 curl_easy_setopt (eh,
409 curl_slist_free_all (all_headers);
410 curl_easy_cleanup (eh);
414 job->job_headers = all_headers;
417 curl_easy_setopt (eh,
421 curl_easy_setopt (eh,
422 CURLOPT_WRITEFUNCTION,
425 curl_easy_setopt (eh,
429 curl_easy_setopt (eh,
433 curl_multi_add_handle (
ctx->multi,
438 curl_easy_cleanup (eh);
441 job->easy_handle = eh;
452 const struct curl_slist *extra_headers)
454 struct curl_slist *all_headers =
job->job_headers;
456 for (
const struct curl_slist *curr = extra_headers;
461 (all_headers = curl_slist_append (all_headers,
464 job->job_headers = all_headers;
476 struct curl_slist *all_headers;
486 job->jcc_raw_cls = jcc_cls;
500 struct curl_slist *all_headers;
503 if ( (NULL !=
ctx->userpass) &&
504 (0 != curl_easy_setopt (eh,
508 if ( (NULL !=
ctx->certfile) &&
509 (0 != curl_easy_setopt (eh,
513 if ( (NULL !=
ctx->certtype) &&
514 (0 != curl_easy_setopt (eh,
518 if ( (NULL !=
ctx->keyfile) &&
519 (0 != curl_easy_setopt (eh,
523 if ( (NULL !=
ctx->keypass) &&
524 (0 != curl_easy_setopt (eh,
537 job->jcc_cls = jcc_cls;
550 struct curl_slist *job_headers = NULL;
553 curl_slist_append (NULL,
554 "Content-Type: application/json")));
560 curl_slist_free_all (job_headers);
588 curl_multi_remove_handle (
ctx->multi,
590 curl_easy_cleanup (
job->easy_handle);
592 curl_slist_free_all (
job->job_headers);
610 if (0 == strcasecmp (ct,
622 if (semi - ct != strlen (
"application/json"))
624 if (0 == strncasecmp (ct,
626 strlen (
"application/json")))
642 "Downloaded body: %.*s\n",
646 curl_easy_getinfo (eh,
647 CURLINFO_RESPONSE_CODE,
655 curl_easy_getinfo (eh,
656 CURLINFO_CONTENT_TYPE,
663 if (0 !=
db->buf_size)
665 "Did NOT detect response `%.*s' as JSON\n",
667 (
const char *)
db->buf);
670 if (MHD_HTTP_NO_CONTENT == *response_code)
672 if (0 == *response_code)
677 curl_easy_getinfo (eh,
678 CURLINFO_EFFECTIVE_URL,
680 url =
"<unknown URL>";
682 "Failed to download response from `%s': \n",
689 json = json_loadb (
db->buf,
691 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
710 ctx->common_headers = curl_slist_append (
ctx->common_headers,
712 if (NULL ==
ctx->common_headers)
728 (void) curl_multi_perform (
ctx->multi,
730 while (NULL != (cmsg = curl_multi_info_read (
ctx->multi,
740 curl_easy_getinfo (cmsg->easy_handle,
745 if (NULL !=
job->jcc_raw)
749 curl_easy_getinfo (
job->easy_handle,
750 CURLINFO_RESPONSE_CODE,
752 job->jcc_raw (
job->jcc_raw_cls,
785 fd_set *write_fd_set,
786 fd_set *except_fd_set,
795 curl_multi_fdset (
ctx->multi,
803 curl_multi_timeout (
ctx->multi,
808 if ((to < *
timeout) && (-1 != to))
810 if ((-1 == (*
timeout)) && (NULL !=
ctx->jobs_head))
820 curl_share_cleanup (
ctx->share);
821 curl_multi_cleanup (
ctx->multi);
822 curl_slist_free_all (
ctx->common_headers);
836 GNUNET_CURL_constructor__ (
void)
840 if (CURLE_OK != (
ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
854 GNUNET_CURL_destructor__ (
void)
858 curl_global_cleanup ();
__attribute__((constructor))
Initial global setup logic, specifically runs the Curl setup.
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.
#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 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.
void * GNUNET_CURL_download_get_result_(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
Create a job.
static int ret
Return value of the commandline.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
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 char * rp
Relying party.
static struct GNUNET_FS_DirectoryBuilder * db
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
#define GNUNET_log(kind,...)
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.
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.
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.
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
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.
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.
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.
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
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.
void GNUNET_CURL_perform(struct GNUNET_CURL_Context *ctx)
Run the main event loop for the CURL interaction.
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.
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...
int 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_RawParser)(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Parses the raw response we got from the Web server.
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...
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.
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.
#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_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.
static unsigned int size
Size of the "table".
static enum GNUNET_NetworkType scope
Which network scope do we belong to?
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.
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.
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.