GNUnet 0.22.2
curl.c File Reference

API for downloading JSON via CURL. More...

#include "platform.h"
#include <jansson.h>
#include <microhttpd.h>
#include "gnunet_curl_lib.h"
#include "curl_internal.h"
Include dependency graph for curl.c:

Go to the source code of this file.

Data Structures

struct  GNUNET_CURL_Job
 Jobs are CURL requests running within a struct GNUNET_CURL_Context. More...
 
struct  GNUNET_CURL_Context
 Context. More...
 

Macros

#define DEBUG   0
 Set to 1 for extra debug logging. More...
 
#define CURL_STRERROR(type, function, code)
 Log error related to CURL operations. More...
 
#define JSON_WARN(error)
 Print JSON parsing related error information. More...
 

Functions

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 performed with ctx. More...
 
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 performed with ctx. More...
 
struct GNUNET_CURL_ContextGNUNET_CURL_init (GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
 Initialise this library. More...
 
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. More...
 
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. More...
 
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. More...
 
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. More...
 
static struct GNUNET_CURL_Jobsetup_job (CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
 Create a job. More...
 
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. More...
 
struct GNUNET_CURL_JobGNUNET_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. More...
 
struct GNUNET_CURL_JobGNUNET_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. More...
 
struct GNUNET_CURL_JobGNUNET_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. More...
 
struct GNUNET_CURL_JobGNUNET_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. More...
 
void GNUNET_CURL_job_cancel (struct GNUNET_CURL_Job *job)
 Cancel a job. More...
 
static bool is_json (const char *ct)
 Test if the given content type ct is JSON. More...
 
void * GNUNET_CURL_download_get_result_ (struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
 
enum GNUNET_GenericReturnValue GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header)
 Add custom request header. More...
 
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. More...
 
void GNUNET_CURL_perform (struct GNUNET_CURL_Context *ctx)
 Run the main event loop for the CURL interaction. More...
 
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. More...
 
void GNUNET_CURL_fini (struct GNUNET_CURL_Context *ctx)
 Cleanup library initialisation resources. More...
 
void GNUNET_CURL_constructor__ (void)
 
void __attribute__ ((constructor))
 Initial global setup logic, specifically runs the Curl setup. More...
 
void GNUNET_CURL_destructor__ (void)
 
void __attribute__ ((destructor))
 Cleans up after us, specifically runs the Curl cleanup. More...
 

Variables

static int curl_fail
 Failsafe flag. More...
 

Detailed Description

API for downloading JSON via CURL.

Author
Sree Harsha Totakura sreeh.nosp@m.arsh.nosp@m.a@tot.nosp@m.akur.nosp@m.a.in
Christian Grothoff

Definition in file curl.c.

Macro Definition Documentation

◆ DEBUG

#define DEBUG   0

Set to 1 for extra debug logging.

Definition at line 39 of file curl.c.

◆ CURL_STRERROR

#define CURL_STRERROR (   type,
  function,
  code 
)
Value:
"Curl function `%s' has failed at `%s:%d' with error: %s\n", \
function, \
__FILE__, \
__LINE__, \
curl_easy_strerror (code));
static uint32_t type
Type string converted to DNS type value.
#define GNUNET_log(kind,...)

Log error related to CURL operations.

Parameters
typelog level
functionwhich function failed to run
codewhat was the curl error code

Definition at line 48 of file curl.c.

◆ JSON_WARN

#define JSON_WARN (   error)
Value:
"JSON parsing failed at %s:%u: %s (%s)\n", \
__FILE__, \
__LINE__, \
error.text, \
error.source)
@ GNUNET_ERROR_TYPE_WARNING

Print JSON parsing related error information.

Definition at line 59 of file curl.c.

Function Documentation

◆ download_cb()

static size_t download_cb ( char *  bufptr,
size_t  size,
size_t  nitems,
void *  cls 
)
static

Callback used when downloading the reply to an HTTP request.

Just appends all of the data to the buf in the struct DownloadBuffer for further processing. The size of the download is limited to GNUNET_MAX_MALLOC_CHECKED, if the download exceeds this size, we abort with an error.

Parameters
bufptrdata downloaded via HTTP
sizesize of an item in bufptr
nitemsnumber of items in bufptr
clsthe struct DownloadBuffer
Returns
number of bytes processed from bufptr

Definition at line 315 of file curl.c.

319{
320 struct GNUNET_CURL_DownloadBuffer *db = cls;
321 size_t msize;
322 void *buf;
323
324 if (0 == size * nitems)
325 {
326 /* Nothing (left) to do */
327 return 0;
328 }
329 msize = size * nitems;
330 if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
331 {
332 db->eno = ENOMEM;
333 return 0; /* signals an error to curl */
334 }
335 db->buf = GNUNET_realloc (db->buf,
336 db->buf_size + msize);
337 buf = db->buf + db->buf_size;
338 GNUNET_memcpy (buf, bufptr, msize);
339 db->buf_size += msize;
340 return msize;
341}
static struct GNUNET_FS_DirectoryBuilder * db
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
static unsigned int size
Size of the "table".
Definition: peer.c:68
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser.
void * buf
Download buffer.

References GNUNET_CURL_DownloadBuffer::buf, db, GNUNET_MAX_MALLOC_CHECKED, GNUNET_memcpy, GNUNET_realloc, and size.

Referenced by setup_job().

Here is the caller graph for this function:

◆ setup_job_headers()

static struct curl_slist * setup_job_headers ( struct GNUNET_CURL_Context ctx,
const struct curl_slist *  job_headers 
)
static

Create the HTTP headers for the request.

Parameters
ctxcontext we run in
job_headersjob-specific headers
Returns
all headers to use

Definition at line 352 of file curl.c.

354{
355 struct curl_slist *all_headers = NULL;
356
357 for (const struct curl_slist *curr = job_headers;
358 NULL != curr;
359 curr = curr->next)
360 {
361 GNUNET_assert (NULL !=
362 (all_headers = curl_slist_append (all_headers,
363 curr->data)));
364 }
365
366 for (const struct curl_slist *curr = ctx->common_headers;
367 NULL != curr;
368 curr = curr->next)
369 {
370 GNUNET_assert (NULL !=
371 (all_headers = curl_slist_append (all_headers,
372 curr->data)));
373 }
374
375 if (NULL != ctx->async_scope_id_header)
376 {
377 struct GNUNET_AsyncScopeSave scope;
378
379 GNUNET_async_scope_get (&scope);
380 if (GNUNET_YES == scope.have_scope)
381 {
382 char *aid_header;
383
384 aid_header =
386 &scope.scope_id,
387 sizeof(struct GNUNET_AsyncScopeId));
388 GNUNET_assert (NULL != aid_header);
389 GNUNET_assert (NULL != curl_slist_append (all_headers,
390 aid_header));
391 GNUNET_free (aid_header);
392 }
393 }
394 return all_headers;
395}
static struct GNUNET_FS_Handle * ctx
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
@ GNUNET_YES
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#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.
Definition: strings.c:787
Identifier for an asynchronous execution context.
Saved async scope identifier or root scope.

References ctx, GNUNET_assert, GNUNET_async_scope_get(), GNUNET_free, GNUNET_STRINGS_data_to_string_alloc(), GNUNET_YES, GNUNET_AsyncScopeSave::have_scope, and GNUNET_AsyncScopeSave::scope_id.

Referenced by GNUNET_CURL_job_add2(), and GNUNET_CURL_job_add_raw().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_job()

static struct GNUNET_CURL_Job * setup_job ( CURL *  eh,
struct GNUNET_CURL_Context ctx,
struct curl_slist *  all_headers 
)
static

Create a job.

Parameters
eheasy handle to use
ctxcontext to run the job in
all_headersHTTP client headers to use (free'd)
Returns
NULL on error

Definition at line 407 of file curl.c.

410{
411 struct GNUNET_CURL_Job *job;
412
413 if (CURLE_OK !=
414 curl_easy_setopt (eh,
415 CURLOPT_HTTPHEADER,
416 all_headers))
417 {
418 GNUNET_break (0);
419 curl_slist_free_all (all_headers);
420 curl_easy_cleanup (eh);
421 return NULL;
422 }
423 job = GNUNET_new (struct GNUNET_CURL_Job);
424 job->start_time = GNUNET_TIME_absolute_get ();
425 job->job_headers = all_headers;
426
427 if ( (CURLE_OK !=
428 curl_easy_setopt (eh,
429 CURLOPT_PRIVATE,
430 job)) ||
431 (CURLE_OK !=
432 curl_easy_setopt (eh,
433 CURLOPT_WRITEFUNCTION,
434 &download_cb)) ||
435 (CURLE_OK !=
436 curl_easy_setopt (eh,
437 CURLOPT_WRITEDATA,
438 &job->db)) ||
439 (CURLE_OK !=
440 curl_easy_setopt (eh,
441 CURLOPT_SHARE,
442 ctx->share)) )
443 {
444 GNUNET_break (0);
446 curl_easy_cleanup (eh);
447 return NULL;
448 }
449 if ( (CURLM_OK !=
450 curl_multi_add_handle (ctx->multi,
451 eh)) )
452 {
453 GNUNET_break (0);
455 curl_easy_cleanup (eh);
456 return NULL;
457 }
458 job->easy_handle = eh;
459 job->ctx = ctx;
461 ctx->jobs_tail,
462 job);
463 return job;
464}
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.
Definition: curl.c:315
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
Definition: gnunet-cadet.c:137
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition: time.c:111
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition: curl.c:78

References ctx, download_cb(), GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_free, GNUNET_new, GNUNET_TIME_absolute_get(), and job.

Referenced by GNUNET_CURL_job_add2(), and GNUNET_CURL_job_add_raw().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ is_json()

static bool is_json ( const char *  ct)
static

Test if the given content type ct is JSON.

Parameters
cta content type, e.g. "application/json; charset=UTF-8"
Returns
true if ct denotes JSON

Definition at line 623 of file curl.c.

624{
625 const char *semi;
626
627 /* check for "application/json" exact match */
628 if (0 == strcasecmp (ct,
629 "application/json"))
630 return true;
631 /* check for "application/json;[ANYTHING]" */
632 semi = strchr (ct,
633 ';');
634 /* also allow "application/json [ANYTHING]" (note the space!) */
635 if (NULL == semi)
636 semi = strchr (ct,
637 ' ');
638 if (NULL == semi)
639 return false; /* no delimiter we accept, forget it */
640 if (semi - ct != strlen ("application/json"))
641 return false; /* delimiter past desired length, forget it */
642 if (0 == strncasecmp (ct,
643 "application/json",
644 strlen ("application/json")))
645 return true; /* OK */
646 return false;
647}

Referenced by GNUNET_CURL_download_get_result_().

Here is the caller graph for this function:

◆ GNUNET_CURL_download_get_result_()

void * GNUNET_CURL_download_get_result_ ( struct GNUNET_CURL_DownloadBuffer db,
CURL *  eh,
long *  response_code 
)

Definition at line 651 of file curl.c.

654{
655 json_t *json;
656 char *ct;
657
658#if DEBUG
660 "Downloaded body: %.*s\n",
661 (int) db->buf_size,
662 (char *) db->buf);
663#endif
664 if (CURLE_OK !=
665 curl_easy_getinfo (eh,
666 CURLINFO_RESPONSE_CODE,
667 response_code))
668 {
669 /* unexpected error... */
670 GNUNET_break (0);
671 *response_code = 0;
672 }
673 if (MHD_HTTP_NO_CONTENT == *response_code)
674 return NULL;
675 if ((CURLE_OK !=
676 curl_easy_getinfo (eh,
677 CURLINFO_CONTENT_TYPE,
678 &ct)) ||
679 (NULL == ct) ||
680 (! is_json (ct)))
681 {
682 /* No content type or explicitly not JSON, refuse to parse
683 (but keep response code) */
684 if (0 != db->buf_size)
685 {
686 const char *url;
687
688 if (CURLE_OK !=
689 curl_easy_getinfo (eh,
690 CURLINFO_EFFECTIVE_URL,
691 &url))
692 url = "<unknown URL>";
694 "Request to `%s' was expected to return a body of type `application/json', got `%s'\n",
695 url,
696 ct);
697 }
698 return NULL;
699 }
700 if (0 == *response_code)
701 {
702 const char *url;
703
704 if (CURLE_OK !=
705 curl_easy_getinfo (eh,
706 CURLINFO_EFFECTIVE_URL,
707 &url))
708 url = "<unknown URL>";
710 "Failed to download response from `%s': \n",
711 url);
712 return NULL;
713 }
714 json = NULL;
715 if (0 == db->eno)
716 {
717 json_error_t error;
718
719 json = json_loadb (db->buf,
720 db->buf_size,
721 JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
722 &error);
723 if (NULL == json)
724 {
725 JSON_WARN (error);
726 *response_code = 0;
728 "Failed to parse JSON response: %s\n",
729 error.text);
730 }
731 }
732 GNUNET_free (db->buf);
733 db->buf = NULL;
734 db->buf_size = 0;
735 return json;
736}
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition: curl.c:623
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition: curl.c:59
@ GNUNET_ERROR_TYPE_DEBUG
@ MHD_HTTP_NO_CONTENT
No Content [RFC7231, Section 6.3.5].

References db, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, is_json(), JSON_WARN, and MHD_HTTP_NO_CONTENT.

Referenced by GNUNET_CURL_gnunet_rc_create(), and GNUNET_CURL_perform().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNUNET_CURL_constructor__()

void GNUNET_CURL_constructor__ ( void  )

◆ __attribute__() [1/2]

void __attribute__ ( (constructor)  )

Initial global setup logic, specifically runs the Curl setup.

Definition at line 888 of file curl.c.

890{
891 CURLcode ret;
892
893 if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
894 {
896 "curl_global_init",
897 ret);
898 curl_fail = 1;
899 }
900}
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition: curl.c:48
static int curl_fail
Failsafe flag.
Definition: curl.c:72
static int ret
Final status code.
Definition: gnunet-arm.c:93
@ GNUNET_ERROR_TYPE_ERROR

References curl_fail, CURL_STRERROR, GNUNET_ERROR_TYPE_ERROR, and ret.

◆ GNUNET_CURL_destructor__()

void GNUNET_CURL_destructor__ ( void  )

◆ __attribute__() [2/2]

void __attribute__ ( (destructor)  )

Cleans up after us, specifically runs the Curl cleanup.

Definition at line 908 of file curl.c.

910{
911 if (curl_fail)
912 return;
913 curl_global_cleanup ();
914}

References curl_fail.

Variable Documentation

◆ curl_fail

int curl_fail
static

Failsafe flag.

Raised if our constructor fails to initialize the Curl library.

Definition at line 72 of file curl.c.

Referenced by __attribute__(), and GNUNET_CURL_init().