GNUnet  0.17.6
Data Structures | Macros | Functions | Variables
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 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 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...
 
int 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...
 
 __attribute__ ((constructor))
 Initial global setup logic, specifically runs the Curl setup. More...
 
 __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

◆ 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));
#define GNUNET_log(kind,...)
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model

Log error related to CURL operations.

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

Definition at line 43 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 54 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 305 of file curl.c.

309 {
310  struct GNUNET_CURL_DownloadBuffer *db = cls;
311  size_t msize;
312  void *buf;
313 
314  if (0 == size * nitems)
315  {
316  /* Nothing (left) to do */
317  return 0;
318  }
319  msize = size * nitems;
320  if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
321  {
322  db->eno = ENOMEM;
323  return 0; /* signals an error to curl */
324  }
325  db->buf = GNUNET_realloc (db->buf,
326  db->buf_size + msize);
327  buf = db->buf + db->buf_size;
328  GNUNET_memcpy (buf, bufptr, msize);
329  db->buf_size += msize;
330  return msize;
331 }
static struct GNUNET_FS_DirectoryBuilder * db
Definition: gnunet-search.c:94
static char buf[2048]
#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:67
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser.

References 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 342 of file curl.c.

344 {
345  struct curl_slist *all_headers = NULL;
346 
347  for (const struct curl_slist *curr = job_headers;
348  NULL != curr;
349  curr = curr->next)
350  {
351  GNUNET_assert (NULL !=
352  (all_headers = curl_slist_append (all_headers,
353  curr->data)));
354  }
355 
356  for (const struct curl_slist *curr = ctx->common_headers;
357  NULL != curr;
358  curr = curr->next)
359  {
360  GNUNET_assert (NULL !=
361  (all_headers = curl_slist_append (all_headers,
362  curr->data)));
363  }
364 
365  if (NULL != ctx->async_scope_id_header)
366  {
368 
370  if (GNUNET_YES == scope.have_scope)
371  {
372  char *aid_header;
373 
374  aid_header =
376  &scope.scope_id,
377  sizeof(struct GNUNET_AsyncScopeId));
378  GNUNET_assert (NULL != aid_header);
379  GNUNET_assert (NULL != curl_slist_append (all_headers,
380  aid_header));
381  GNUNET_free (aid_header);
382  }
383  }
384  return all_headers;
385 }
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
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:764
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.

References ctx, GNUNET_assert, GNUNET_async_scope_get(), GNUNET_free, GNUNET_STRINGS_data_to_string_alloc(), GNUNET_YES, and scope.

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 397 of file curl.c.

400 {
401  struct GNUNET_CURL_Job *job;
402 
403  if (CURLE_OK !=
404  curl_easy_setopt (eh,
405  CURLOPT_HTTPHEADER,
406  all_headers))
407  {
408  GNUNET_break (0);
409  curl_slist_free_all (all_headers);
410  curl_easy_cleanup (eh);
411  return NULL;
412  }
413  job = GNUNET_new (struct GNUNET_CURL_Job);
414  job->job_headers = all_headers;
415 
416  if ( (CURLE_OK !=
417  curl_easy_setopt (eh,
418  CURLOPT_PRIVATE,
419  job)) ||
420  (CURLE_OK !=
421  curl_easy_setopt (eh,
422  CURLOPT_WRITEFUNCTION,
423  &download_cb)) ||
424  (CURLE_OK !=
425  curl_easy_setopt (eh,
426  CURLOPT_WRITEDATA,
427  &job->db)) ||
428  (CURLE_OK !=
429  curl_easy_setopt (eh,
430  CURLOPT_SHARE,
431  ctx->share)) )
432  {
433  GNUNET_break (0);
434  GNUNET_free (job);
435  curl_easy_cleanup (eh);
436  return NULL;
437  }
438  if ( (CURLM_OK !=
439  curl_multi_add_handle (ctx->multi,
440  eh)) )
441  {
442  GNUNET_break (0);
443  GNUNET_free (job);
444  curl_easy_cleanup (eh);
445  return NULL;
446  }
447  job->easy_handle = eh;
448  job->ctx = ctx;
449  GNUNET_CONTAINER_DLL_insert (ctx->jobs_head,
450  ctx->jobs_tail,
451  job);
452  return job;
453 }
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:305
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.
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition: curl.c:73

References ctx, download_cb(), GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_free, GNUNET_new, 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 611 of file curl.c.

612 {
613  const char *semi;
614 
615  /* check for "application/json" exact match */
616  if (0 == strcasecmp (ct,
617  "application/json"))
618  return true;
619  /* check for "application/json;[ANYTHING]" */
620  semi = strchr (ct,
621  ';');
622  /* also allow "application/json [ANYTHING]" (note the space!) */
623  if (NULL == semi)
624  semi = strchr (ct,
625  ' ');
626  if (NULL == semi)
627  return false; /* no delimiter we accept, forget it */
628  if (semi - ct != strlen ("application/json"))
629  return false; /* delimiter past desired length, forget it */
630  if (0 == strncasecmp (ct,
631  "application/json",
632  strlen ("application/json")))
633  return true; /* OK */
634  return false;
635 }

Referenced by GNUNET_CURL_append_header().

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 639 of file curl.c.

642 {
643  json_t *json;
644  json_error_t error;
645  char *ct;
646 
648  "Downloaded body: %.*s\n",
649  (int) db->buf_size,
650  (char *) db->buf);
651  if (CURLE_OK !=
652  curl_easy_getinfo (eh,
653  CURLINFO_RESPONSE_CODE,
654  response_code))
655  {
656  /* unexpected error... */
657  GNUNET_break (0);
658  *response_code = 0;
659  }
660  if ((CURLE_OK !=
661  curl_easy_getinfo (eh,
662  CURLINFO_CONTENT_TYPE,
663  &ct)) ||
664  (NULL == ct) ||
665  (! is_json (ct)))
666  {
667  /* No content type or explicitly not JSON, refuse to parse
668  (but keep response code) */
669  if (0 != db->buf_size)
671  "Did NOT detect response `%.*s' as JSON\n",
672  (int) db->buf_size,
673  (const char *) db->buf);
674  return NULL;
675  }
676  if (MHD_HTTP_NO_CONTENT == *response_code)
677  return NULL;
678  if (0 == *response_code)
679  {
680  char *url;
681 
682  if (CURLE_OK !=
683  curl_easy_getinfo (eh,
684  CURLINFO_EFFECTIVE_URL,
685  &url))
686  url = "<unknown URL>";
688  "Failed to download response from `%s': \n",
689  url);
690  return NULL;
691  }
692  json = NULL;
693  if (0 == db->eno)
694  {
695  json = json_loadb (db->buf,
696  db->buf_size,
697  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
698  &error);
699  if (NULL == json)
700  {
701  JSON_WARN (error);
702  *response_code = 0;
703  }
704  }
705  GNUNET_free (db->buf);
706  db->buf = NULL;
707  db->buf_size = 0;
708  return json;
709 }
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition: curl.c:611
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition: curl.c:54
@ GNUNET_ERROR_TYPE_DEBUG

Referenced by GNUNET_CURL_gnunet_rc_create(), and GNUNET_CURL_perform().

Here is the caller graph for this function:

◆ __attribute__() [1/2]

__attribute__ ( (constructor)  )

Initial global setup logic, specifically runs the Curl setup.

Definition at line 841 of file curl.c.

843 {
844  CURLcode ret;
845 
846  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
847  {
849  "curl_global_init",
850  ret);
851  curl_fail = 1;
852  }
853 }
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition: curl.c:43
static int curl_fail
Failsafe flag.
Definition: curl.c:67
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
@ GNUNET_ERROR_TYPE_ERROR

References curl_fail, CURL_STRERROR, GNUNET_ERROR_TYPE_ERROR, and ret.

◆ __attribute__() [2/2]

__attribute__ ( (destructor)  )

Cleans up after us, specifically runs the Curl cleanup.

Definition at line 859 of file curl.c.

861 {
862  if (curl_fail)
863  return;
864  curl_global_cleanup ();
865 }

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 67 of file curl.c.

Referenced by __attribute__(), and GNUNET_CURL_init().