GNUnet  0.11.x
curl.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2014, 2015, 2016, 2018 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
26 #include "platform.h"
27 #include <jansson.h>
28 #include <microhttpd.h>
29 #include "gnunet_curl_lib.h"
30 
31 #if ENABLE_BENCHMARK
32 #include "../util/benchmark.h"
33 #endif
34 
35 
43 #define CURL_STRERROR(type, function, code) \
44  GNUNET_log (type, \
45  "Curl function `%s' has failed at `%s:%d' with error: %s\n", \
46  function, \
47  __FILE__, \
48  __LINE__, \
49  curl_easy_strerror (code));
50 
54 #define JSON_WARN(error) \
55  GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
56  "JSON parsing failed at %s:%u: %s (%s)\n", \
57  __FILE__, \
58  __LINE__, \
59  error.text, \
60  error.source)
61 
62 
67 static int curl_fail;
68 
73 {
78 
83 
87  CURL *easy_handle;
88 
93 
98 
102  void *jcc_cls;
103 
108 
112  void *jcc_raw_cls;
113 
118 
123  struct curl_slist *job_headers;
124 };
125 
126 
131 {
135  CURLM *multi;
136 
140  CURLSH *share;
141 
146 
151 
155  struct curl_slist *common_headers;
156 
162 
168 
172  void *cb_cls;
173 };
174 
175 
184 struct GNUNET_CURL_Context *
186  void *cb_cls)
187 {
188  struct GNUNET_CURL_Context *ctx;
189  CURLM *multi;
190  CURLSH *share;
191 
192  if (curl_fail)
193  {
195  "Curl was not initialised properly\n");
196  return NULL;
197  }
198  if (NULL == (multi = curl_multi_init ()))
199  {
201  "Failed to create a Curl multi handle\n");
202  return NULL;
203  }
204  if (NULL == (share = curl_share_init ()))
205  {
207  "Failed to create a Curl share handle\n");
208  return NULL;
209  }
210  ctx = GNUNET_new (struct GNUNET_CURL_Context);
211  ctx->cb = cb;
212  ctx->cb_cls = cb_cls;
213  ctx->multi = multi;
214  ctx->share = share;
215  return ctx;
216 }
217 
218 
225 void
227  const char *header_name)
228 {
229  ctx->async_scope_id_header = header_name;
230 }
231 
232 
242 int
243 GNUNET_CURL_is_valid_scope_id (const char *scope_id)
244 {
245  if (strlen (scope_id) >= 64)
246  return GNUNET_NO;
247  for (size_t i = 0; i < strlen (scope_id); i++)
248  if (! (isalnum (scope_id[i]) || (scope_id[i] == '-')))
249  return GNUNET_NO;
250  return GNUNET_YES;
251 }
252 
253 
267 static size_t
268 download_cb (char *bufptr,
269  size_t size,
270  size_t nitems,
271  void *cls)
272 {
273  struct GNUNET_CURL_DownloadBuffer *db = cls;
274  size_t msize;
275  void *buf;
276 
277  if (0 == size * nitems)
278  {
279  /* Nothing (left) to do */
280  return 0;
281  }
282  msize = size * nitems;
283  if ((msize + db->buf_size) >= GNUNET_MAX_MALLOC_CHECKED)
284  {
285  db->eno = ENOMEM;
286  return 0; /* signals an error to curl */
287  }
288  db->buf = GNUNET_realloc (db->buf, db->buf_size + msize);
289  buf = db->buf + db->buf_size;
290  GNUNET_memcpy (buf, bufptr, msize);
291  db->buf_size += msize;
292  return msize;
293 }
294 
295 
303 static struct curl_slist *
305  const struct curl_slist *job_headers)
306 {
307  struct curl_slist *all_headers = NULL;
308 
309  for (const struct curl_slist *curr = job_headers; curr != NULL;
310  curr = curr->next)
311  {
312  GNUNET_assert (NULL !=
313  (all_headers = curl_slist_append (all_headers, curr->data)));
314  }
315 
316  for (const struct curl_slist *curr = ctx->common_headers; curr != NULL;
317  curr = curr->next)
318  {
319  GNUNET_assert (NULL !=
320  (all_headers = curl_slist_append (all_headers, curr->data)));
321  }
322 
323  if (NULL != ctx->async_scope_id_header)
324  {
325  struct GNUNET_AsyncScopeSave scope;
326 
327  GNUNET_async_scope_get (&scope);
328  if (GNUNET_YES == scope.have_scope)
329  {
330  char *aid_header = NULL;
331  aid_header =
333  sizeof(
334  struct GNUNET_AsyncScopeId));
335  GNUNET_assert (NULL != aid_header);
336  GNUNET_assert (NULL != curl_slist_append (all_headers, aid_header));
337  GNUNET_free (aid_header);
338  }
339  }
340  return all_headers;
341 }
342 
343 
352 static struct GNUNET_CURL_Job *
353 setup_job (CURL *eh,
354  struct GNUNET_CURL_Context *ctx,
355  struct curl_slist *all_headers)
356 {
357  struct GNUNET_CURL_Job *job;
358 
359  if (CURLE_OK !=
360  curl_easy_setopt (eh, CURLOPT_HTTPHEADER, all_headers))
361  {
362  GNUNET_break (0);
363  curl_slist_free_all (all_headers);
364  curl_easy_cleanup (eh);
365  return NULL;
366  }
367  job = GNUNET_new (struct GNUNET_CURL_Job);
368  job->job_headers = all_headers;
369 
370  if ((CURLE_OK != curl_easy_setopt (eh, CURLOPT_PRIVATE, job)) ||
371  (CURLE_OK !=
372  curl_easy_setopt (eh, CURLOPT_WRITEFUNCTION, &download_cb)) ||
373  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_WRITEDATA, &job->db)) ||
374  (CURLE_OK != curl_easy_setopt (eh, CURLOPT_SHARE, ctx->share)) ||
375  (CURLM_OK != curl_multi_add_handle (ctx->multi, eh)))
376  {
377  GNUNET_break (0);
378  GNUNET_free (job);
379  curl_easy_cleanup (eh);
380  return NULL;
381  }
382  job->easy_handle = eh;
383  job->ctx = ctx;
385  ctx->jobs_tail,
386  job);
387  return job;
388 }
389 
390 
406 struct GNUNET_CURL_Job *
408  CURL *eh,
409  const struct curl_slist *job_headers,
411  void *jcc_cls)
412 {
413  struct GNUNET_CURL_Job *job;
414  struct curl_slist *all_headers;
415 
416  GNUNET_assert (NULL != jcc);
417  all_headers = setup_job_headers (ctx,
418  job_headers);
419  if (NULL == (job = setup_job (eh,
420  ctx,
421  all_headers)))
422  return NULL;
423  job->jcc_raw = jcc;
424  job->jcc_raw_cls = jcc_cls;
425  ctx->cb (ctx->cb_cls);
426  return job;
427 }
428 
429 
449 struct GNUNET_CURL_Job *
451  CURL *eh,
452  const struct curl_slist *job_headers,
454  void *jcc_cls)
455 {
456  struct GNUNET_CURL_Job *job;
457  struct curl_slist *all_headers;
458 
459  GNUNET_assert (NULL != jcc);
460  all_headers = setup_job_headers (ctx,
461  job_headers);
462  if (NULL == (job = setup_job (eh,
463  ctx,
464  all_headers)))
465  return NULL;
466 
467  job->jcc = jcc;
468  job->jcc_cls = jcc_cls;
469  ctx->cb (ctx->cb_cls);
470  return job;
471 }
472 
473 
490 struct GNUNET_CURL_Job *
492  CURL *eh,
493  int add_json,
495  void *jcc_cls)
496 {
497  struct GNUNET_CURL_Job *job;
498  struct curl_slist *job_headers = NULL;
499 
500  if (GNUNET_YES == add_json)
501  {
502  GNUNET_assert (
503  NULL != (job_headers =
504  curl_slist_append (NULL, "Content-Type: application/json")));
505  }
506 
507  job = GNUNET_CURL_job_add2 (ctx,
508  eh,
509  job_headers,
510  jcc,
511  jcc_cls);
512  curl_slist_free_all (job_headers);
513  return job;
514 }
515 
516 
523 void
525 {
526  struct GNUNET_CURL_Context *ctx = job->ctx;
527 
529  GNUNET_break (CURLM_OK ==
530  curl_multi_remove_handle (ctx->multi, job->easy_handle));
531  curl_easy_cleanup (job->easy_handle);
532  GNUNET_free (job->db.buf);
533  curl_slist_free_all (job->job_headers);
534  ctx->cb (ctx->cb_cls);
535  GNUNET_free (job);
536 }
537 
538 
545 static bool
546 is_json (const char *ct)
547 {
548  const char *semi;
549 
550  /* check for "application/json" exact match */
551  if (0 == strcasecmp (ct,
552  "application/json"))
553  return true;
554  /* check for "application/json;[ANYTHING]" */
555  semi = strchr (ct,
556  ';');
557  /* also allow "application/json [ANYTHING]" (note the space!) */
558  if (NULL == semi)
559  semi = strchr (ct,
560  ' ');
561  if (NULL == semi)
562  return false; /* no delimiter we accept, forget it */
563  if (semi - ct != strlen ("application/json"))
564  return false; /* delimiter past desired length, forget it */
565  if (0 == strncasecmp (ct,
566  "application/json",
567  strlen ("application/json")))
568  return true; /* OK */
569  return false;
570 }
571 
572 
591 void *
593  CURL *eh,
594  long *response_code)
595 {
596  json_t *json;
597  json_error_t error;
598  char *ct;
599 
601  "Downloaded body: %.*s\n",
602  (int) db->buf_size,
603  (char *) db->buf);
604 
605  if ((CURLE_OK !=
606  curl_easy_getinfo (eh,
607  CURLINFO_CONTENT_TYPE,
608  &ct)) ||
609  (NULL == ct) ||
610  (! is_json (ct)))
611  {
612  /* No content type or explicitly not JSON, refuse to parse
613  (but keep response code) */
614  if (CURLE_OK !=
615  curl_easy_getinfo (eh,
616  CURLINFO_RESPONSE_CODE,
617  response_code))
618  {
619  /* unexpected error... */
620  GNUNET_break (0);
621  *response_code = 0;
622  }
623  if (0 != db->buf_size)
625  "Did NOT detect response `%.*s' as JSON\n",
626  (int) db->buf_size,
627  (const char *) db->buf);
628  return NULL;
629  }
630  if (MHD_HTTP_NO_CONTENT == *response_code)
631  return NULL;
632  json = NULL;
633  if (0 == db->eno)
634  {
635  json = json_loadb (db->buf,
636  db->buf_size,
637  JSON_REJECT_DUPLICATES | JSON_DISABLE_EOF_CHECK,
638  &error);
639  if (NULL == json)
640  {
641  JSON_WARN (error);
642  *response_code = 0;
643  }
644  }
645  GNUNET_free (db->buf);
646  db->buf = NULL;
647  db->buf_size = 0;
648  if (NULL != json)
649  {
650  if (CURLE_OK !=
651  curl_easy_getinfo (eh,
652  CURLINFO_RESPONSE_CODE,
653  response_code))
654  {
655  /* unexpected error... */
656  GNUNET_break (0);
657  *response_code = 0;
658  }
659  }
660  return json;
661 }
662 
663 
671 int
672 GNUNET_CURL_append_header (struct GNUNET_CURL_Context *ctx, const char *header)
673 {
674  ctx->common_headers = curl_slist_append (ctx->common_headers, header);
675  if (NULL == ctx->common_headers)
676  return GNUNET_SYSERR;
677 
678  return GNUNET_OK;
679 }
680 
681 
682 #if ENABLE_BENCHMARK
683 static void
684 do_benchmark (CURLMsg *cmsg)
685 {
686  char *url = NULL;
687  double total_as_double = 0;
688  struct GNUNET_TIME_Relative total;
689  struct UrlRequestData *urd;
690  /* Some care required, as curl is using data types (long vs curl_off_t vs
691  * double) inconsistently to store byte count. */
692  curl_off_t size_curl = 0;
693  long size_long = 0;
694  uint64_t bytes_sent = 0;
695  uint64_t bytes_received = 0;
696 
697  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
698  CURLINFO_TOTAL_TIME,
699  &total_as_double));
700  total.rel_value_us = total_as_double * 1000 * 1000;
701 
702  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
703  CURLINFO_EFFECTIVE_URL,
704  &url));
705 
706  /* HEADER_SIZE + SIZE_DOWNLOAD_T is hopefully the total
707  number of bytes received, not clear from curl docs. */
708 
709  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
710  CURLINFO_HEADER_SIZE,
711  &size_long));
712  bytes_received += size_long;
713 
714  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
715  CURLINFO_SIZE_DOWNLOAD_T,
716  &size_curl));
717  bytes_received += size_curl;
718 
719  /* REQUEST_SIZE + SIZE_UPLOAD_T is hopefully the total number of bytes
720  sent, again docs are not completely clear. */
721 
722  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
723  CURLINFO_REQUEST_SIZE,
724  &size_long));
725  bytes_sent += size_long;
726 
727  /* We obtain this value to check an invariant, but never use it otherwise. */
728  GNUNET_break (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
729  CURLINFO_SIZE_UPLOAD_T,
730  &size_curl));
731 
732  /* CURLINFO_SIZE_UPLOAD_T <= CURLINFO_REQUEST_SIZE should
733  be an invariant.
734  As verified with
735  curl -w "foo%{size_request} -XPOST --data "ABC" $URL
736  the CURLINFO_REQUEST_SIZE should be the whole size of the request
737  including headers and body.
738  */GNUNET_break (size_curl <= size_long);
739 
740  urd = get_url_benchmark_data (url, (unsigned int) response_code);
741  urd->count++;
742  urd->time = GNUNET_TIME_relative_add (urd->time, total);
743  urd->time_max = GNUNET_TIME_relative_max (total, urd->time_max);
744  urd->bytes_sent += bytes_sent;
746 }
747 
748 
749 #endif
750 
751 
760 void
764 {
765  CURLMsg *cmsg;
766  int n_running;
767  int n_completed;
768 
769  (void) curl_multi_perform (ctx->multi,
770  &n_running);
771  while (NULL != (cmsg = curl_multi_info_read (ctx->multi, &n_completed)))
772  {
773  struct GNUNET_CURL_Job *job;
774  long response_code;
775  void *response;
776 
777  /* Only documented return value is CURLMSG_DONE */
778  GNUNET_break (CURLMSG_DONE == cmsg->msg);
779  GNUNET_assert (CURLE_OK == curl_easy_getinfo (cmsg->easy_handle,
780  CURLINFO_PRIVATE,
781  (char **) &job));
782  GNUNET_assert (job->ctx == ctx);
783  response_code = 0;
784  if (NULL != job->jcc_raw)
785  {
786  /* RAW mode, no parsing */
787  GNUNET_break (CURLE_OK ==
788  curl_easy_getinfo (job->easy_handle,
789  CURLINFO_RESPONSE_CODE,
790  &response_code));
791  job->jcc_raw (job->jcc_raw_cls,
792  response_code,
793  job->db.buf,
794  job->db.buf_size);
795  }
796  else
797  {
798  /* to be parsed via 'rp' */
799  response = rp (&job->db,
800  job->easy_handle,
801  &response_code);
802  job->jcc (job->jcc_cls,
803  response_code,
804  response);
805  rc (response);
806  }
807 #if ENABLE_BENCHMARK
808  do_benchmark (cmsg);
809 #endif
811  }
812 }
813 
814 
820 void
822 {
825  (GNUNET_CURL_ResponseCleaner) & json_decref);
826 }
827 
828 
857 void
859  fd_set *read_fd_set,
860  fd_set *write_fd_set,
861  fd_set *except_fd_set,
862  int *max_fd,
863  long *timeout)
864 {
865  long to;
866  int m;
867 
868  m = -1;
869  GNUNET_assert (CURLM_OK == curl_multi_fdset (ctx->multi,
870  read_fd_set,
871  write_fd_set,
872  except_fd_set,
873  &m));
874  to = *timeout;
875  *max_fd = GNUNET_MAX (m, *max_fd);
876  GNUNET_assert (CURLM_OK == curl_multi_timeout (ctx->multi, &to));
877 
878  /* Only if what we got back from curl is smaller than what we
879  already had (-1 == infinity!), then update timeout */
880  if ((to < *timeout) && (-1 != to))
881  *timeout = to;
882  if ((-1 == (*timeout)) && (NULL != ctx->jobs_head))
883  *timeout = to;
884 }
885 
886 
894 void
896 {
897  /* all jobs must have been cancelled at this time, assert this */
898  GNUNET_assert (NULL == ctx->jobs_head);
899  curl_share_cleanup (ctx->share);
900  curl_multi_cleanup (ctx->multi);
901  curl_slist_free_all (ctx->common_headers);
902  GNUNET_free (ctx);
903 }
904 
905 
909 __attribute__ ((constructor)) void
910 GNUNET_CURL_constructor__ (void)
911 {
912  CURLcode ret;
913 
914  if (CURLE_OK != (ret = curl_global_init (CURL_GLOBAL_DEFAULT)))
915  {
916  CURL_STRERROR (GNUNET_ERROR_TYPE_ERROR, "curl_global_init", ret);
917  curl_fail = 1;
918  }
919 }
920 
921 
925 __attribute__ ((destructor)) void
926 GNUNET_CURL_destructor__ (void)
927 {
928  if (curl_fail)
929  return;
930  curl_global_cleanup ();
931 }
932 
933 
934 /* end of curl.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define CURL_STRERROR(type, function, code)
Log error related to CURL operations.
Definition: curl.c:43
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.
Definition: curl.c:450
uint64_t rel_value_us
The actual value.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
library to make it easy to download JSON replies over HTTP
struct GNUNET_TIME_Relative GNUNET_TIME_relative_max(struct GNUNET_TIME_Relative t1, struct GNUNET_TIME_Relative t2)
Return the maximum of two relative time values.
Definition: time.c:287
struct GNUNET_CURL_Job * prev
We keep jobs in a DLL.
Definition: curl.c:82
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
int GNUNET_CURL_is_valid_scope_id(const char *scope_id)
Return GNUNET_YES if given a valid scope ID and GNUNET_NO otherwise.
Definition: curl.c:243
int GNUNET_CURL_append_header(struct GNUNET_CURL_Context *ctx, const char *header)
Add custom request header.
Definition: curl.c:672
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
void GNUNET_CURL_fini(struct GNUNET_CURL_Context *ctx)
Cleanup library initialisation resources.
Definition: curl.c:895
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Identifier for an asynchronous execution context.
Struct for benchmark data for one URL.
Definition: benchmark.h:65
GNUNET_CURL_RescheduleCallback cb
Function we need to call whenever the event loop&#39;s socket set changed.
Definition: curl.c:167
struct GNUNET_TIME_Relative time_max
Slowest time to response.
Definition: benchmark.h:100
void(* GNUNET_CURL_JobCompletionCallback)(void *cls, long response_code, const void *response)
Function to call upon completion of a job.
void GNUNET_CURL_job_cancel(struct GNUNET_CURL_Job *job)
Cancel a job.
Definition: curl.c:524
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
uint64_t count
How often was the URL requested?
Definition: benchmark.h:80
void * jcc_cls
Closure for jcc.
Definition: curl.c:102
static struct GNUNET_ARM_MonitorHandle * m
Monitor connection with ARM.
Definition: gnunet-arm.c:104
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.
Definition: curl.c:407
void *(* GNUNET_CURL_RawParser)(struct GNUNET_CURL_DownloadBuffer *db, CURL *eh, long *response_code)
Parses the raw response we got from the Web server.
GNUNET_CURL_JobCompletionCallback jcc
Function to call upon completion.
Definition: curl.c:97
struct GNUNET_CURL_Job * jobs_head
We keep jobs in a DLL.
Definition: curl.c:145
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
#define GNUNET_realloc(ptr, size)
Wrapper around realloc.
struct GNUNET_CURL_Job * next
We keep jobs in a DLL.
Definition: curl.c:77
#define JSON_WARN(error)
Print JSON parsing related error information.
Definition: curl.c:54
#define GNUNET_MAX(a, b)
Definition: gnunet_common.h:95
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.
Definition: curl.c:304
static CURLM * multi
Current multi-CURL handle.
CURLSH * share
Curl share handle.
Definition: curl.c:140
static char buf[2048]
static int curl_fail
Failsafe flag.
Definition: curl.c:67
Context.
Definition: curl.c:130
uint64_t bytes_sent
How many bytes were sent in total to request the URL.
Definition: benchmark.h:85
struct GNUNET_TIME_Relative time
Total time spent requesting this URL.
Definition: benchmark.h:95
void GNUNET_async_scope_get(struct GNUNET_AsyncScopeSave *scope_ret)
Get the current async scope.
GNUNET_CURL_RawJobCompletionCallback jcc_raw
Function to call upon completion.
Definition: curl.c:107
void(* GNUNET_CURL_ResponseCleaner)(void *response)
Deallocate the response.
__attribute__((constructor))
Initial global setup logic, specifically runs the Curl setup.
Definition: curl.c:909
CURLM * multi
Curl multi handle.
Definition: curl.c:135
static unsigned int size
Size of the "table".
Definition: peer.c:67
uint64_t bytes_received
How many bytes were received in total as response to requesting this URL.
Definition: benchmark.h:90
int have_scope
GNUNET_YES unless this saved scope is the unnamed root scope.
Saved async scope identifier or root scope.
CURL * easy_handle
Easy handle of the job.
Definition: curl.c:87
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
static struct GNUNET_SCHEDULER_Task * job
Task for main job.
Definition: gnunet-cadet.c:137
struct GNUNET_TIME_Relative GNUNET_TIME_relative_add(struct GNUNET_TIME_Relative a1, struct GNUNET_TIME_Relative a2)
Add relative times together.
Definition: time.c:579
static bool is_json(const char *ct)
Test if the given content type ct is JSON.
Definition: curl.c:546
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...
Definition: curl.c:858
Buffer data structure we use to buffer the HTTP download before giving it to the JSON parser...
struct GNUNET_AsyncScopeId scope_id
Saved scope.
void GNUNET_CURL_perform(struct GNUNET_CURL_Context *ctx)
Run the main event loop for the HTTP interaction.
Definition: curl.c:821
void * buf
Download buffer.
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 * cb_cls
Closure for cb.
Definition: curl.c:172
Jobs are CURL requests running within a struct GNUNET_CURL_Context.
Definition: curl.c:72
#define GNUNET_log(kind,...)
struct GNUNET_CURL_Context * GNUNET_CURL_init(GNUNET_CURL_RescheduleCallback cb, void *cb_cls)
Initialise this library.
Definition: curl.c:185
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
static char * rp
Relying party.
struct GNUNET_CURL_Job * jobs_tail
We keep jobs in a DLL.
Definition: curl.c:150
static struct MHD_Response * response
Our canonical response.
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.
struct GNUNET_CURL_DownloadBuffer db
Buffer for response received from CURL.
Definition: curl.c:117
struct UrlRequestData * get_url_benchmark_data(char *url, unsigned int status)
Get benchmark data for a URL.
Definition: benchmark.c:241
struct GNUNET_CURL_Job * GNUNET_CURL_job_add(struct GNUNET_CURL_Context *ctx, CURL *eh, int add_json, GNUNET_CURL_JobCompletionCallback jcc, void *jcc_cls)
Schedule a CURL request to be executed and call the given jcc upon its completion.
Definition: curl.c:491
char * GNUNET_STRINGS_data_to_string_alloc(const void *buf, size_t size)
Return the base32crockford encoding of the given buffer.
Definition: strings.c:935
size_t buf_size
The size of the download buffer.
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.
Definition: curl.c:761
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
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.
Definition: curl.c:226
void * jcc_raw_cls
Closure for jcc_raw.
Definition: curl.c:112
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CURL_Context * ctx
Context this job runs in.
Definition: curl.c:92
struct curl_slist * common_headers
Headers common for all requests in the context.
Definition: curl.c:155
static struct GNUNET_CURL_Job * setup_job(CURL *eh, struct GNUNET_CURL_Context *ctx, struct curl_slist *all_headers)
Create a job.
Definition: curl.c:353
Time for relative time used by GNUnet, in microseconds.
int eno
Error code (based on libc errno) if we failed to download (i.e.
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.
Definition: curl.c:592
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:268