DTS Application Library  0.2.3
Application library containing referenced objects and interfaces to common libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Groups Pages
curl.c
Go to the documentation of this file.
1 
7 #include <string.h>
8 #include <stdint.h>
9 #include <stdlib.h>
10 
11 #include <curl/curl.h>
12 #include <curl/easy.h>
13 
14 #include "dtsapp.h"
15 
16 static void *curl_isinit = NULL;
17 static CURL *curl = NULL;
18 
20 static struct curl_progress {
22  void *data;
29 } *curlprogress = NULL;
30 
32 static struct curl_password {
34  curl_authcb authcb;
36  void *data;
37 } *curlpassword = NULL;
38 
40 struct curl_post {
42  struct curl_httppost *first;
44  struct curl_httppost *last;
45 };
46 
47 static size_t bodytobuffer(void *ptr, size_t size, size_t nmemb, void *userdata) {
48  size_t bufsize = size * nmemb;
49  struct curlbuf *mem = (struct curlbuf *)userdata;
50 
51  if (!(mem->body = realloc(mem->body, mem->bsize + bufsize + 1))) {
52  return 0;
53  }
54  memcpy(&(mem->body[mem->bsize]), ptr, bufsize);
55  mem->bsize += bufsize;
56  mem->body[mem->bsize] = '\0';
57  return bufsize;
58 }
59 
60 static size_t headertobuffer(void *ptr, size_t size, size_t nmemb, void *userdata) {
61  size_t bufsize = size * nmemb;
62  struct curlbuf *mem = (struct curlbuf *)userdata;
63 
64  if (!(mem->header = realloc(mem->header, mem->hsize + bufsize + 1))) {
65  return 0;
66  }
67  memcpy(&(mem->header[mem->hsize]), ptr, bufsize);
68  mem->hsize += bufsize;
69  mem->header[mem->hsize] = '\0';
70  return bufsize;
71 }
72 
73 static void curlfree(void *data) {
74  if (curl) {
75  curl_easy_cleanup(curl);
76  curl = NULL;
77  }
78  if (curlprogress) {
79  objunref(curlprogress);
80  curlprogress = NULL;
81  }
82  if (curlpassword) {
83  objunref(curlpassword);
84  curlpassword = NULL;
85  }
86 }
87 
92 int curlinit(void) {
93  if (curl_isinit) {
94  return objref(curl_isinit);
95  }
96 
97  if (!(curl_isinit = objalloc(sizeof(void *),curlfree))) {
98  return 0;
99  }
100 
101  objlock(curl_isinit);
102  if (!(curl = curl_easy_init())) {
103  objunlock(curl_isinit);
104  objunref(curl_isinit);
105  return 0;
106  }
107 
108  curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
109  curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
110  curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
111 
112  curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcurl-agent/1.0 [Distro Solutions]");
113 
114  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, bodytobuffer);
115  curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headertobuffer);
116  objunlock(curl_isinit);
117  return 1;
118 }
119 
122 void curlclose(void) {
123  objunref(curl_isinit);
124  curl_isinit = NULL;
125 }
126 
127 static void emptybuffer(void *data) {
128  struct curlbuf *writebuf = data;
129 
130  if (!writebuf) {
131  return;
132  }
133 
134  if (writebuf->body) {
135  free(writebuf->body);
136  }
137 
138  if (writebuf->header) {
139  free(writebuf->header);
140  }
141 
142  writebuf->body = NULL;
143  writebuf->header = NULL;
144  writebuf->bsize = 0;
145  writebuf->hsize = 0;
146 }
147 
148 static struct curlbuf *curl_sendurl(const char *def_url, struct basic_auth *bauth, struct curl_post *post, curl_authcb authcb_in,void *auth_data_in) {
149  long res;
150  int i = 0;
151  struct basic_auth *auth = bauth;
152  struct curlbuf *writebuf;
153  char userpass[64];
154  char *url;
155  void *p_data = NULL;
156  curl_authcb authcb = authcb_in;
157  void *auth_data = auth_data_in;
158  /* char buffer[1024];
159  struct curl_slist *cookies, *nc;*/
160 
161  if (!curlinit()) {
162  return NULL;
163  }
164 
165  if (!(writebuf = objalloc(sizeof(*writebuf), emptybuffer))) {
166  objunref(curl_isinit);
167  return NULL;
168  }
169 
170  objlock(curl_isinit);
171  curl_easy_setopt(curl, CURLOPT_URL, def_url);
172  /* curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buffer);*/
173 
174  curl_easy_setopt(curl, CURLOPT_WRITEDATA, writebuf);
175  curl_easy_setopt(curl, CURLOPT_WRITEHEADER, writebuf);
176 
177  if (post) {
178  objlock(post);
179  curl_easy_setopt(curl, CURLOPT_HTTPPOST, post->first);
180  }
181 
182  if (auth && auth->user && auth->passwd) {
183  snprintf(userpass, 63, "%s:%s", auth->user, auth->passwd);
184  curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
185  i++;
186  } else if (!auth) {
187  auth = curl_newauth(NULL, NULL);
188  }
189 
190  if (curlprogress && ((p_data = curlprogress->d_cb(curlprogress->data)))) {
191  curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
192  curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curlprogress->cb);
193  curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, p_data);
194  }
195 
196  if (curlpassword && !authcb) {
197  authcb = curlpassword->authcb;
198  auth_data = curlpassword->data;
199  }
200 
201  do {
202  if (!(res = curl_easy_perform(curl))) {
203  curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &res);
204  switch (res) {
205  /*needs auth*/
206  case 401:
207  if (curlprogress && curlprogress->p_cb) {
208  curlprogress->p_cb(p_data, 1);
209  }
210  if ((authcb) && ((auth = authcb((auth) ? auth->user : "", (auth) ? auth->passwd : "", auth_data)))) {
211  snprintf(userpass, 63, "%s:%s", auth->user, auth->passwd);
212  curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
213  emptybuffer(writebuf);
214  } else {
215  i=3;
216  }
217 
218  if (curlprogress && curlprogress->p_cb) {
219  curlprogress->p_cb(p_data, 0);
220  }
221  break;
222  /*not found*/
223  case 300:
224  i=3;
225  break;
226  /*redirect*/
227  case 301:
228  curl_easy_getinfo(curl,CURLINFO_REDIRECT_URL, &url);
229  curl_easy_setopt(curl, CURLOPT_URL, url);
230  emptybuffer(writebuf);
231  i--;
232  break;
233  /*ok*/
234  case 200:
235  curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &writebuf->c_type);
236  break;
237  }
238  }
239  i++;
240  } while ((res != 200) && (i < 3));
241 
242  /* curl_easy_getinfo(curl, CURLINFO_COOKIELIST, &cookies);
243  for(nc = cookies; nc; nc=nc->next) {
244  printf("%s\n", nc->data);
245  }*/
246 
247  if (!bauth) {
248  objunref(auth);
249  }
250 
251  if (post) {
252  objunlock(post);
253  objunref(post);
254  }
255 
256  if (curlprogress && curlprogress->p_cb) {
257  curlprogress->p_cb(p_data, -1);
258  }
259 
260  if (p_data) {
261  objunref(p_data);
262  }
263 
264  objunlock(curl_isinit);
265  objunref(curl_isinit);
266  return writebuf;
267 }
268 
276 struct curlbuf *curl_geturl(const char *def_url, struct basic_auth *bauth, curl_authcb authcb,void *auth_data) {
277  return curl_sendurl(def_url, bauth, NULL, authcb, auth_data);
278 }
279 
288 struct curlbuf *curl_posturl(const char *def_url, struct basic_auth *bauth, struct curl_post *post, curl_authcb authcb,void *auth_data) {
289  return curl_sendurl(def_url, bauth, post, authcb, auth_data);
290 }
291 
295 struct curlbuf *curl_ungzip(struct curlbuf *cbuf) {
296  uint8_t *gzbuf;
297  uint32_t len;
298 
299  if (is_gzip((uint8_t *)cbuf->body, cbuf->bsize) &&
300  ((gzbuf = gzinflatebuf((uint8_t *)cbuf->body, cbuf->bsize, &len)))) {
301  free(cbuf->body);
302  cbuf->body = gzbuf;
303  cbuf->bsize = len;
304  }
305  return cbuf;
306 }
307 
308 static void curl_freeauth(void *data) {
309  struct basic_auth *bauth = (struct basic_auth *)data;
310  if (!bauth) {
311  return;
312  }
313  if (bauth->user) {
314  memset((void *)bauth->user, 0, strlen(bauth->user));
315  free((void *)bauth->user);
316  }
317  if (bauth->passwd) {
318  memset((void *)bauth->passwd, 0, strlen(bauth->passwd));
319  free((void *)bauth->passwd);
320  }
321 }
322 
328 struct basic_auth *curl_newauth(const char *user, const char *passwd) {
329  struct basic_auth *bauth;
330 
331  if (!(bauth = (struct basic_auth *)objalloc(sizeof(*bauth), curl_freeauth))) {
332  return NULL;
333  }
334  if (user) {
335  bauth->user = strdup(user);
336  } else {
337  bauth->user = strdup("");
338  }
339  if (passwd) {
340  bauth->passwd = strdup(passwd);
341  } else {
342  bauth->passwd = strdup("");
343  }
344  return bauth;
345 }
346 
347 static void free_post(void *data) {
348  struct curl_post *post = data;
349  if (post->first) {
350  curl_formfree(post->first);
351  }
352 }
353 
356 extern struct curl_post *curl_newpost(void) {
357  struct curl_post *post;
358  if (!(post = objalloc(sizeof(*post), free_post))) {
359  return NULL;
360  }
361  post->first = NULL;
362  post->last = NULL;
363  return post;
364 }
365 
370 void curl_postitem(struct curl_post *post, const char *name, const char *value) {
371  if (!name || !value) {
372  return;
373  }
374  objlock(post);
375  curl_formadd(&post->first, &post->last,
376  CURLFORM_COPYNAME, name,
377  CURLFORM_COPYCONTENTS, value,
378  CURLFORM_END);
379  objunlock(post);
380 }
381 
385 extern char *url_escape(char *url) {
386  char *esc;
387  char *ret = NULL;
388 
389  if (!curlinit()) {
390  return NULL;
391  }
392 
393  objlock(curl_isinit);
394  esc = curl_easy_escape(curl, url, 0);
395  if (esc) {
396  ret = strdup(esc);
397  }
398  curl_free(esc);
399  objunlock(curl_isinit);
400  objunref(curl_isinit);
401  return ret;
402 }
403 
407 extern char *url_unescape(char *url) {
408  char *uesc;
409  char *ret = NULL;
410 
411  if (!curlinit()) {
412  return NULL;
413  }
414 
415  objlock(curl_isinit);
416  uesc = curl_easy_unescape(curl, url, 0, 0);
417  if (uesc) {
418  ret = strdup(uesc);
419  }
420  curl_free(uesc);
421  objunlock(curl_isinit);
422  objunref(curl_isinit);
423  return ret;
424 }
425 
426 static void free_progress(void *data) {
427  struct curl_progress *prg = data;
428  if (prg->data) {
429  objunref(prg->data);
430  }
431 }
432 
443  if (curlprogress) {
444  objunref(curlprogress);
445  curlprogress = NULL;
446  }
447 
448  if (!(curlprogress = objalloc(sizeof(*curlprogress), free_progress))) {
449  return;
450  }
451  curlprogress->cb = cb;
452  curlprogress->d_cb = d_cb;
453  curlprogress->p_cb = p_cb;
454  if (data && objref(data)) {
455  curlprogress->data = data;
456  }
457 }
458 
459 static void free_curlpassword(void *data) {
460  struct curl_password *cpwd = data;
461  if (cpwd->data) {
462  objunref(cpwd->data);
463  }
464 }
465 
470 void curl_setauth_cb(curl_authcb auth_cb, void *data) {
471  if (curlpassword) {
472  objunref(curlpassword);
473  curlpassword = NULL;
474  }
475 
476  if (!(curlpassword = objalloc(sizeof(*curlpassword), free_curlpassword))) {
477  return;
478  }
479 
480  curlpassword->authcb = auth_cb;
481  if (data && objref(data)) {
482  curlpassword->data = data;
483  }
484 }
485 
489 extern struct xml_doc *curl_buf2xml(struct curlbuf *cbuf) {
490  struct xml_doc *xmldoc = NULL;
491 
492  if (cbuf && cbuf->c_type && !strcmp("application/xml", cbuf->c_type)) {
493  curl_ungzip(cbuf);
494  xmldoc = xml_loadbuf(cbuf->body, cbuf->bsize, 1);
495  }
496  return xmldoc;
497 }
498 
Basic authentification structure.
Definition: dtsapp.h:824
void curl_setauth_cb(curl_authcb auth_cb, void *data)
Set global password callback.
Definition: curl.c:470
struct basic_auth * curl_newauth(const char *user, const char *passwd)
Create a new auth structure with initial vallues.
Definition: curl.c:328
int objref(void *data)
Reference a object.
Definition: refobj.c:153
struct xml_doc xml_doc
Forward decleration of structure.
Definition: dtsapp.h:631
struct curlbuf * curl_geturl(const char *def_url, struct basic_auth *bauth, curl_authcb authcb, void *auth_data)
Fetch the URL using CURL (HTTP GET)
Definition: curl.c:276
int objlock(void *data)
Lock the reference.
Definition: refobj.c:269
Buffer containing the result of a curl transaction.
Definition: dtsapp.h:832
HTTP post data structure.
Definition: curl.c:40
struct curl_httppost * last
Last item in the list.
Definition: curl.c:44
int(* curl_progress_func)(void *, double, double, double, double)
CURL callback function called when there is progress (CURLOPT_PROGRESSFUNCTION).
Definition: dtsapp.h:862
struct xml_doc * xml_loadbuf(const uint8_t *buffer, uint32_t len, int validate)
Load a buffer into XML document returning refereence.
Definition: libxml2.c:168
const char * user
Username.
Definition: dtsapp.h:826
uint8_t * gzinflatebuf(uint8_t *buf_in, int buf_size, uint32_t *len)
Ungzip a buffer.
Definition: zlib.c:101
uint8_t * body
Body buffer.
Definition: dtsapp.h:836
void * objalloc(int size, objdestroy)
Allocate a referenced lockable object.
Definition: refobj.c:129
size_t hsize
Header size.
Definition: dtsapp.h:840
void curlclose(void)
Un reference CURL. This is required for each call to curlinit().
Definition: curl.c:122
void curl_postitem(struct curl_post *post, const char *name, const char *value)
Add a item value pair to post structure.
Definition: curl.c:370
struct curlbuf * curl_ungzip(struct curlbuf *cbuf)
If the buffer contains GZIP data uncompress it.
Definition: curl.c:295
struct curl_httppost * first
First item in the list.
Definition: curl.c:42
int curlinit(void)
Initilise the CURL library.
Definition: curl.c:92
DTS Application library API Include file.
char * c_type
Mime Type.
Definition: dtsapp.h:838
struct curl_post * curl_newpost(void)
Create a HTTP Post data structure.
Definition: curl.c:356
void *(* curl_progress_newdata)(void *)
Create a new progress data structure.
Definition: dtsapp.h:876
char * url_escape(char *url)
Escape and return the url.
Definition: curl.c:385
char * url_unescape(char *url)
UN escape and return the url.
Definition: curl.c:407
uint8_t * header
Header buffer.
Definition: dtsapp.h:834
struct curlbuf * curl_posturl(const char *def_url, struct basic_auth *bauth, struct curl_post *post, curl_authcb authcb, void *auth_data)
Fetch the URL using CURL (HTTP POST)
Definition: curl.c:288
void(* curl_progress_pause)(void *, int)
Callback function to control the progress bar.
Definition: dtsapp.h:867
struct basic_auth *(* curl_authcb)(const char *, const char *, void *)
Callback to set the authentification ie on error 401.
Definition: dtsapp.h:853
int objunlock(void *data)
Unlock a reference.
Definition: refobj.c:301
const char * passwd
Password.
Definition: dtsapp.h:828
void curl_setprogress(curl_progress_func cb, curl_progress_pause p_cb, curl_progress_newdata d_cb, void *data)
Configure global progress handling.
Definition: curl.c:442
int is_gzip(uint8_t *buf, int buf_size)
check a buffer if it contains gzip magic
Definition: zlib.c:85
size_t bsize
Body size.
Definition: dtsapp.h:842
int objunref(void *data)
Drop reference held.
Definition: refobj.c:184
struct xml_doc * curl_buf2xml(struct curlbuf *cbuf)
Create a XML document from from buffer (application/xml)
Definition: curl.c:489