GNUnet  0.11.x
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)
 Obtain information about the final result about the HTTP download. More...
 
int 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 HTTP 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.

Referenced by __attribute__().

◆ JSON_WARN

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

Print JSON parsing related error information.

Definition at line 54 of file curl.c.

Referenced by GNUNET_CURL_download_get_result_().

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

References GNUNET_CURL_DownloadBuffer::buf, buf, GNUNET_CURL_DownloadBuffer::buf_size, GNUNET_CURL_Job::db, GNUNET_CURL_DownloadBuffer::eno, GNUNET_MAX_MALLOC_CHECKED, GNUNET_memcpy, and GNUNET_realloc.

Referenced by setup_job().

355 {
356  struct GNUNET_CURL_DownloadBuffer *db = cls;
357  size_t msize;
358  void *buf;
359 
360  if (0 == size * nitems)
361  {
362  /* Nothing (left) to do */
363  return 0;
364  }
365  msize = size * nitems;
366  if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
367  {
368  db->eno = ENOMEM;
369  return 0; /* signals an error to curl */
370  }
371  db->buf = GNUNET_realloc (db->buf, db->buf_size + msize);
372  buf = db->buf + db->buf_size;
373  GNUNET_memcpy (buf, bufptr, msize);
374  db->buf_size += msize;
375  return msize;
376 }
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
static char buf[2048]
static unsigned int size
Size of the "table".
Definition: peer.c:67
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser...
static struct GNUNET_FS_DirectoryBuilder * db
Definition: gnunet-search.c:41
void * buf
Download buffer.
size_t buf_size
The size of the download buffer.
int eno
Error code (based on libc errno) if we failed to download (e.g.
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 387 of file curl.c.

References GNUNET_CURL_Context::async_scope_id_header, GNUNET_CURL_Context::common_headers, 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().

389 {
390  struct curl_slist *all_headers = NULL;
391 
392  for (const struct curl_slist *curr = job_headers;
393  NULL != curr;
394  curr = curr->next)
395  {
396  GNUNET_assert (NULL !=
397  (all_headers = curl_slist_append (all_headers,
398  curr->data)));
399  }
400 
401  for (const struct curl_slist *curr = ctx->common_headers;
402  NULL != curr;
403  curr = curr->next)
404  {
405  GNUNET_assert (NULL !=
406  (all_headers = curl_slist_append (all_headers,
407  curr->data)));
408  }
409 
410  if (NULL != ctx->async_scope_id_header)
411  {
413 
415  if (GNUNET_YES == scope.have_scope)
416  {
417  char *aid_header;
418 
419  aid_header =
421  &scope.scope_id,
422  sizeof(struct GNUNET_AsyncScopeId));
423  GNUNET_assert (NULL != aid_header);
424  GNUNET_assert (NULL != curl_slist_append (all_headers, aid_header));
425  GNUNET_free (aid_header);
426  }
427  }
428  return all_headers;
429 }
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
Identifier for an asynchronous execution context.
static enum GNUNET_NetworkType scope
Which network scope do we belong to?
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
Saved async scope identifier or root scope.
const char * async_scope_id_header
If non-NULL, the async scope ID is sent in a request header of this name.
Definition: curl.c:161
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:937
#define GNUNET_free(ptr)
Wrapper around free.
struct curl_slist * common_headers
Headers common for all requests in the context.
Definition: curl.c:155
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 441 of file curl.c.

References GNUNET_CURL_Job::ctx, GNUNET_CURL_Job::db, download_cb(), GNUNET_CURL_Job::easy_handle, GNUNET_break, GNUNET_CONTAINER_DLL_insert, GNUNET_free, GNUNET_new, job, GNUNET_CURL_Job::job_headers, GNUNET_CURL_Context::jobs_head, GNUNET_CURL_Context::jobs_tail, GNUNET_CURL_Context::multi, and GNUNET_CURL_Context::share.

Referenced by GNUNET_CURL_job_add2(), and GNUNET_CURL_job_add_raw().

444 {
445  struct GNUNET_CURL_Job *job;
446 
447  if (CURLE_OK !=
448  curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers))
449  {
450  GNUNET_break (0);
451  curl_slist_free_all (all_headers);
452  curl_easy_cleanup (eh);
453  return NULL;
454  }
455  job = GNUNET_new (struct GNUNET_CURL_Job);
456  job->job_headers = all_headers;
457 
458  if ((CURLE_OK != curl_easy_setopt (eh, CURLOPT_PRIVATE, job)) ||
459  (CURLE_OK !=
460  curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, &download_cb)) ||
461  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_WRITEDATA, &job->db)) ||
462  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_SHARE, ctx->share)) ||
463  (CURLM_OK != curl_multi_add_handle (ctx->multi, eh)))
464  {
465  GNUNET_break (0);
466  GNUNET_free (job);
467  curl_easy_cleanup (eh);
468  return NULL;
469  }
470  job->easy_handle = eh;
471  job->ctx = ctx;
473  ctx->jobs_tail,
474  job);
475  return job;
476 }
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
static struct GNUNET_DNSSTUB_Context * ctx
Context for DNS resolution.
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
Definition: curl.c:145
CURLSH * share
Curl share handle.
Definition: curl.c:140
CURLM * multi
Curl multi handle.
Definition: curl.c:135
CURL * easy_handle
Easy handle of the job.
Definition: curl.c:87
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
Definition: gnunet-cadet.c:137
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition: curl.c:72
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
Definition: curl.c:150
struct GNUNET_CURL_DownloadBuffer db
Buffer for response received from CURL.
Definition: curl.c:117
struct curl_slist * job_headers
Headers used for this job, the list needs to be freed after the job has finished. ...
Definition: curl.c:123
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CURL_Context * ctx
Context this job runs in.
Definition: curl.c:92
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:351
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 704 of file curl.c.

Referenced by GNUNET_CURL_download_get_result_().

705 {
706  const char *semi;
707 
708  /* check for "application/json" exact match */
709  if (0 == strcasecmp (ct,
710  "application/json"))
711  return true;
712  /* check for "application/json;[ANYTHING]" */
713  semi = strchr (ct,
714  ';');
715  /* also allow "application/json [ANYTHING]" (note the space!) */
716  if (NULL == semi)
717  semi = strchr (ct,
718  ' ');
719  if (NULL == semi)
720  return false; /* no delimiter we accept, forget it */
721  if (semi - ct != strlen ("application/json"))
722  return false; /* delimiter past desired length, forget it */
723  if (0 == strncasecmp (ct,
724  "application/json",
725  strlen ("application/json")))
726  return true; /* OK */
727  return false;
728 }
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 
)

Obtain information about the final result about the HTTP download.

If the download was successful, parses the JSON in the db and returns it. Also returns the HTTP response_code. If the download failed, the return value is NULL. The response code is set in any case, on download errors to zero.

Calling this function also cleans up db.

Parameters
dbdownload buffer
ehCURL handle (to get the response code)
[out]response_codeset to the HTTP response code (or zero if we aborted the download, for example because the response was too big, or if the JSON we received was malformed).
Returns
NULL if downloading a JSON reply failed.

Definition at line 750 of file curl.c.

References GNUNET_CURL_DownloadBuffer::buf, GNUNET_CURL_DownloadBuffer::buf_size, GNUNET_CURL_DownloadBuffer::eno, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, is_json(), and JSON_WARN.

Referenced by GNUNET_CURL_gnunet_rc_create(), and GNUNET_CURL_perform().

753 {
754  json_t *json;
755  json_error_t error;
756  char *ct;
757 
759  "Downloaded body: %.*s\n",
760  (int) db->buf_size,
761  (char *) db->buf);
762 
763  if ((CURLE_OK !=
764  curl_easy_getinfo (eh,
765  CURLINFO_CONTENT_TYPE,
766  &ct)) ||
767  (NULL == ct) ||
768  (! is_json (ct)))
769  {
770  /* No content type or explicitly not JSON, refuse to parse
771  (but keep response code) */
772  if (CURLE_OK !=
773  curl_easy_getinfo (eh,
774  CURLINFO_RESPONSE_CODE,
775  response_code))
776  {
777  /* unexpected error... */
778  GNUNET_break (0);
779  *response_code = 0;
780  }
781  if (0 != db->buf_size)
783  "Did NOT detect response `%.*s' as JSON\n",
784  (int) db->buf_size,
785  (const char *) db->buf);
786  return NULL;
787  }
788  if (MHD_HTTP_NO_CONTENT == *response_code)
789  return NULL;
790  json = NULL;
791  if (0 == db->eno)
792  {
793  json = json_loadb (db->buf,
794  db->buf_size,
795  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
796  &error);
797  if (NULL == json)
798  {
799  JSON_WARN (error);
800  *response_code = 0;
801  }
802  }
803  GNUNET_free (db->buf);
804  db->buf = NULL;
805  db->buf_size = 0;
806  if (NULL != json)
807  {
808  if (CURLE_OK !=
809  curl_easy_getinfo (eh,
810  CURLINFO_RESPONSE_CODE,
811  response_code))
812  {
813  /* unexpected error... */
814  GNUNET_break (0);
815  *response_code = 0;
816  }
817  }
818  return json;
819 }
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition: curl.c:54
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition: curl.c:704
void * buf
Download buffer.
#define GNUNET_log(kind,...)
size_t buf_size
The size of the download buffer.
#define GNUNET_free(ptr)
Wrapper around free.
int eno
Error code (based on libc errno) if we failed to download (e.g.
Here is the call graph for this function:
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 1073 of file curl.c.

References curl_fail, CURL_STRERROR, GNUNET_ERROR_TYPE_ERROR, and ret.

1075 {
1076  CURLcode ret;
1077 
1078  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
1079  {
1080  CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret);
1081  curl_fail = 1;
1082  }
1083 }
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition: curl.c:43
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static int curl_fail
Failsafe flag.
Definition: curl.c:67

◆ __attribute__() [2/2]

__attribute__ ( (destructor)  )

Cleans up after us, specifically runs the Curl cleanup.

Definition at line 1089 of file curl.c.

References curl_fail.

1091 {
1092  if (curl_fail)
1093  return;
1094  curl_global_cleanup ();
1095 }
static int curl_fail
Failsafe flag.
Definition: curl.c:67

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().