diff options
author | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
commit | dd7595a3475407a7fa96a97393bae8c5220e8762 (patch) | |
tree | e341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/ecore/src/lib/ecore_con/ecore_con_url.c | |
parent | Add the skeleton. (diff) | |
download | SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2 SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz |
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
Diffstat (limited to '')
-rw-r--r-- | libraries/ecore/src/lib/ecore_con/ecore_con_url.c | 1572 |
1 files changed, 1572 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_con/ecore_con_url.c b/libraries/ecore/src/lib/ecore_con/ecore_con_url.c new file mode 100644 index 0000000..cfcf095 --- /dev/null +++ b/libraries/ecore/src/lib/ecore_con/ecore_con_url.c | |||
@@ -0,0 +1,1572 @@ | |||
1 | /* | ||
2 | * For info on how to use libcurl, see: | ||
3 | * http://curl.haxx.se/libcurl/c/libcurl-tutorial.html | ||
4 | */ | ||
5 | |||
6 | /* | ||
7 | * FIXME: Support more CURL features... | ||
8 | */ | ||
9 | |||
10 | #ifdef HAVE_CONFIG_H | ||
11 | # include <config.h> | ||
12 | #endif | ||
13 | |||
14 | #include <string.h> | ||
15 | #include <errno.h> | ||
16 | #include <sys/stat.h> | ||
17 | #include <sys/types.h> | ||
18 | #include <unistd.h> | ||
19 | |||
20 | #ifdef HAVE_WS2TCPIP_H | ||
21 | # include <ws2tcpip.h> | ||
22 | #endif | ||
23 | |||
24 | #ifdef HAVE_ESCAPE | ||
25 | # include <Escape.h> | ||
26 | #endif | ||
27 | |||
28 | #include "Ecore.h" | ||
29 | #include "ecore_private.h" | ||
30 | #include "Ecore_Con.h" | ||
31 | #include "ecore_con_private.h" | ||
32 | |||
33 | int ECORE_CON_EVENT_URL_DATA = 0; | ||
34 | int ECORE_CON_EVENT_URL_COMPLETE = 0; | ||
35 | int ECORE_CON_EVENT_URL_PROGRESS = 0; | ||
36 | |||
37 | #ifdef HAVE_CURL | ||
38 | static Eina_Bool _ecore_con_url_fd_handler(void *data, | ||
39 | Ecore_Fd_Handler *fd_handler); | ||
40 | static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con); | ||
41 | static size_t _ecore_con_url_header_cb(void *ptr, | ||
42 | size_t size, | ||
43 | size_t nitems, | ||
44 | void *stream); | ||
45 | static size_t _ecore_con_url_data_cb(void *buffer, | ||
46 | size_t size, | ||
47 | size_t nitems, | ||
48 | void *userp); | ||
49 | static int _ecore_con_url_progress_cb(void *clientp, | ||
50 | double dltotal, | ||
51 | double dlnow, | ||
52 | double ultotal, | ||
53 | double ulnow); | ||
54 | static size_t _ecore_con_url_read_cb(void *ptr, | ||
55 | size_t size, | ||
56 | size_t nitems, | ||
57 | void *stream); | ||
58 | static void _ecore_con_event_url_free(void *data __UNUSED__, | ||
59 | void *ev); | ||
60 | static int _ecore_con_url_process_completed_jobs( | ||
61 | Ecore_Con_Url *url_con_to_match); | ||
62 | static Eina_Bool _ecore_con_url_idler_handler(void *data); | ||
63 | |||
64 | static Ecore_Idler *_fd_idler_handler = NULL; | ||
65 | static Eina_List *_url_con_list = NULL; | ||
66 | static CURLM *_curlm = NULL; | ||
67 | static fd_set _current_fd_set; | ||
68 | static int _init_count = 0; | ||
69 | static Ecore_Timer *_curl_timeout = NULL; | ||
70 | static Eina_Bool pipelining = EINA_FALSE; | ||
71 | |||
72 | typedef struct _Ecore_Con_Url_Event Ecore_Con_Url_Event; | ||
73 | struct _Ecore_Con_Url_Event | ||
74 | { | ||
75 | int type; | ||
76 | void *ev; | ||
77 | }; | ||
78 | |||
79 | static Eina_Bool | ||
80 | _url_complete_idler_cb(void *data) | ||
81 | { | ||
82 | Ecore_Con_Url_Event *lev; | ||
83 | |||
84 | lev = data; | ||
85 | ecore_event_add(lev->type, lev->ev, _ecore_con_event_url_free, NULL); | ||
86 | free(lev); | ||
87 | |||
88 | return ECORE_CALLBACK_CANCEL; | ||
89 | } | ||
90 | |||
91 | static void | ||
92 | _url_complete_push_event(int type, | ||
93 | void *ev) | ||
94 | { | ||
95 | Ecore_Con_Url_Event *lev; | ||
96 | |||
97 | lev = malloc(sizeof(Ecore_Con_Url_Event)); | ||
98 | lev->type = type; | ||
99 | lev->ev = ev; | ||
100 | |||
101 | ecore_idler_add(_url_complete_idler_cb, lev); | ||
102 | } | ||
103 | |||
104 | #endif | ||
105 | |||
106 | /** | ||
107 | * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions | ||
108 | * | ||
109 | * @{ | ||
110 | */ | ||
111 | |||
112 | EAPI int | ||
113 | ecore_con_url_init(void) | ||
114 | { | ||
115 | #ifdef HAVE_CURL | ||
116 | _init_count++; | ||
117 | |||
118 | if (_init_count > 1) | ||
119 | return _init_count; | ||
120 | |||
121 | if (!ECORE_CON_EVENT_URL_DATA) | ||
122 | { | ||
123 | ECORE_CON_EVENT_URL_DATA = ecore_event_type_new(); | ||
124 | ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new(); | ||
125 | ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new(); | ||
126 | } | ||
127 | |||
128 | if (!_curlm) | ||
129 | { | ||
130 | long ms; | ||
131 | |||
132 | FD_ZERO(&_current_fd_set); | ||
133 | if (curl_global_init(CURL_GLOBAL_ALL)) | ||
134 | { | ||
135 | while (_url_con_list) | ||
136 | ecore_con_url_free(eina_list_data_get(_url_con_list)); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | _curlm = curl_multi_init(); | ||
141 | if (!_curlm) | ||
142 | { | ||
143 | while (_url_con_list) | ||
144 | ecore_con_url_free(eina_list_data_get(_url_con_list)); | ||
145 | |||
146 | _init_count--; | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | curl_multi_timeout(_curlm, &ms); | ||
151 | if (ms <= 0) | ||
152 | ms = 1000; | ||
153 | |||
154 | _curl_timeout = | ||
155 | ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler, | ||
156 | (void *)0xACE); | ||
157 | ecore_timer_freeze(_curl_timeout); | ||
158 | } | ||
159 | |||
160 | return 1; | ||
161 | #else | ||
162 | return 0; | ||
163 | #endif | ||
164 | } | ||
165 | |||
166 | EAPI int | ||
167 | ecore_con_url_shutdown(void) | ||
168 | { | ||
169 | #ifdef HAVE_CURL | ||
170 | if (!_init_count) | ||
171 | return 0; | ||
172 | |||
173 | _init_count--; | ||
174 | |||
175 | if (_init_count != 0) | ||
176 | return _init_count; | ||
177 | |||
178 | if (_fd_idler_handler) | ||
179 | ecore_idler_del(_fd_idler_handler); | ||
180 | |||
181 | _fd_idler_handler = NULL; | ||
182 | |||
183 | if (_curl_timeout) | ||
184 | ecore_timer_del(_curl_timeout); | ||
185 | |||
186 | _curl_timeout = NULL; | ||
187 | |||
188 | while (_url_con_list) | ||
189 | ecore_con_url_free(eina_list_data_get(_url_con_list)); | ||
190 | |||
191 | if (_curlm) | ||
192 | { | ||
193 | curl_multi_cleanup(_curlm); | ||
194 | _curlm = NULL; | ||
195 | } | ||
196 | |||
197 | curl_global_cleanup(); | ||
198 | #endif | ||
199 | return 1; | ||
200 | } | ||
201 | |||
202 | EAPI void | ||
203 | ecore_con_url_pipeline_set(Eina_Bool enable) | ||
204 | { | ||
205 | #ifdef HAVE_CURL | ||
206 | if (enable) | ||
207 | curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, 1); | ||
208 | else | ||
209 | curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, 0); | ||
210 | pipelining = enable; | ||
211 | #else | ||
212 | return; | ||
213 | (void)enable; | ||
214 | #endif | ||
215 | } | ||
216 | |||
217 | EAPI Eina_Bool | ||
218 | ecore_con_url_pipeline_get(void) | ||
219 | { | ||
220 | #ifdef HAVE_CURL | ||
221 | return pipelining; | ||
222 | #endif | ||
223 | return EINA_FALSE; | ||
224 | } | ||
225 | |||
226 | EAPI Ecore_Con_Url * | ||
227 | ecore_con_url_new(const char *url) | ||
228 | { | ||
229 | #ifdef HAVE_CURL | ||
230 | Ecore_Con_Url *url_con; | ||
231 | CURLcode ret; | ||
232 | |||
233 | if (!_init_count) | ||
234 | return NULL; | ||
235 | |||
236 | url_con = calloc(1, sizeof(Ecore_Con_Url)); | ||
237 | if (!url_con) | ||
238 | return NULL; | ||
239 | |||
240 | url_con->fd = -1; | ||
241 | url_con->write_fd = -1; | ||
242 | |||
243 | url_con->curl_easy = curl_easy_init(); | ||
244 | if (!url_con->curl_easy) | ||
245 | { | ||
246 | free(url_con); | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | ECORE_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL); | ||
251 | |||
252 | if (!ecore_con_url_url_set(url_con, url)) | ||
253 | { | ||
254 | ecore_con_url_free(url_con); | ||
255 | return NULL; | ||
256 | } | ||
257 | |||
258 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate"); | ||
259 | if (ret != CURLE_OK) | ||
260 | { | ||
261 | ERR("Could not set CURLOPT_ENCODING to \"gzip,deflate\": %s", | ||
262 | curl_easy_strerror(ret)); | ||
263 | ecore_con_url_free(url_con); | ||
264 | return NULL; | ||
265 | } | ||
266 | |||
267 | curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEFUNCTION, | ||
268 | _ecore_con_url_data_cb); | ||
269 | curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEDATA, url_con); | ||
270 | |||
271 | curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, | ||
272 | _ecore_con_url_progress_cb); | ||
273 | curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSDATA, url_con); | ||
274 | curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_FALSE); | ||
275 | |||
276 | curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERFUNCTION, | ||
277 | _ecore_con_url_header_cb); | ||
278 | curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERDATA, url_con); | ||
279 | |||
280 | /* | ||
281 | * FIXME: Check that these timeouts are sensible defaults | ||
282 | * FIXME: Provide a means to change these timeouts | ||
283 | */ | ||
284 | curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30); | ||
285 | curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1); | ||
286 | |||
287 | return url_con; | ||
288 | #else | ||
289 | return NULL; | ||
290 | url = NULL; | ||
291 | #endif | ||
292 | } | ||
293 | |||
294 | EAPI Ecore_Con_Url * | ||
295 | ecore_con_url_custom_new(const char *url, | ||
296 | const char *custom_request) | ||
297 | { | ||
298 | #ifdef HAVE_CURL | ||
299 | Ecore_Con_Url *url_con; | ||
300 | CURLcode ret; | ||
301 | |||
302 | if (!url) | ||
303 | return NULL; | ||
304 | |||
305 | if (!custom_request) | ||
306 | return NULL; | ||
307 | |||
308 | url_con = ecore_con_url_new(url); | ||
309 | |||
310 | if (!url_con) | ||
311 | return NULL; | ||
312 | |||
313 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_CUSTOMREQUEST, custom_request); | ||
314 | if (ret != CURLE_OK) | ||
315 | { | ||
316 | ERR("Could not set a custom request string: %s", | ||
317 | curl_easy_strerror(ret)); | ||
318 | ecore_con_url_free(url_con); | ||
319 | return NULL; | ||
320 | } | ||
321 | |||
322 | return url_con; | ||
323 | #else | ||
324 | return NULL; | ||
325 | url = NULL; | ||
326 | custom_request = NULL; | ||
327 | #endif | ||
328 | } | ||
329 | |||
330 | EAPI void | ||
331 | ecore_con_url_free(Ecore_Con_Url *url_con) | ||
332 | { | ||
333 | #ifdef HAVE_CURL | ||
334 | char *s; | ||
335 | CURLMcode ret; | ||
336 | |||
337 | if (!url_con) | ||
338 | return; | ||
339 | |||
340 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
341 | { | ||
342 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_free"); | ||
343 | return; | ||
344 | } | ||
345 | |||
346 | ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE); | ||
347 | if(url_con->fd != -1) | ||
348 | { | ||
349 | FD_CLR(url_con->fd, &_current_fd_set); | ||
350 | if (url_con->fd_handler) | ||
351 | ecore_main_fd_handler_del(url_con->fd_handler); | ||
352 | |||
353 | url_con->fd = -1; | ||
354 | url_con->fd_handler = NULL; | ||
355 | } | ||
356 | |||
357 | if (url_con->curl_easy) | ||
358 | { | ||
359 | // FIXME: For an unknown reason, progress continue to arrive after destruction | ||
360 | // this prevent any further call to the callback. | ||
361 | curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL); | ||
362 | curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE); | ||
363 | |||
364 | if (url_con->active) | ||
365 | { | ||
366 | url_con->active = EINA_FALSE; | ||
367 | |||
368 | ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); | ||
369 | if (ret != CURLM_OK) | ||
370 | ERR("curl_multi_remove_handle failed: %s", | ||
371 | curl_multi_strerror(ret)); | ||
372 | } | ||
373 | |||
374 | curl_easy_cleanup(url_con->curl_easy); | ||
375 | } | ||
376 | |||
377 | _url_con_list = eina_list_remove(_url_con_list, url_con); | ||
378 | curl_slist_free_all(url_con->headers); | ||
379 | EINA_LIST_FREE(url_con->additional_headers, s) | ||
380 | free(s); | ||
381 | EINA_LIST_FREE(url_con->response_headers, s) | ||
382 | free(s); | ||
383 | eina_stringshare_del(url_con->url); | ||
384 | free(url_con); | ||
385 | #else | ||
386 | return; | ||
387 | (void)url_con; | ||
388 | #endif | ||
389 | } | ||
390 | |||
391 | EAPI const char * | ||
392 | ecore_con_url_url_get(Ecore_Con_Url *url_con) | ||
393 | { | ||
394 | #ifdef HAVE_CURL | ||
395 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
396 | { | ||
397 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__); | ||
398 | return NULL; | ||
399 | } | ||
400 | return url_con->url; | ||
401 | #else | ||
402 | return NULL; | ||
403 | (void)url_con; | ||
404 | #endif | ||
405 | } | ||
406 | |||
407 | EAPI Eina_Bool | ||
408 | ecore_con_url_url_set(Ecore_Con_Url *url_con, | ||
409 | const char *url) | ||
410 | { | ||
411 | #ifdef HAVE_CURL | ||
412 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
413 | { | ||
414 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_url_set"); | ||
415 | return EINA_FALSE; | ||
416 | } | ||
417 | |||
418 | if (url_con->active) | ||
419 | return EINA_FALSE; | ||
420 | |||
421 | eina_stringshare_replace(&url_con->url, url); | ||
422 | |||
423 | if (url_con->url) | ||
424 | curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, | ||
425 | url_con->url); | ||
426 | else | ||
427 | curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, ""); | ||
428 | |||
429 | return EINA_TRUE; | ||
430 | #else | ||
431 | return EINA_FALSE; | ||
432 | (void)url; | ||
433 | (void)url_con; | ||
434 | #endif | ||
435 | } | ||
436 | |||
437 | EAPI void | ||
438 | ecore_con_url_data_set(Ecore_Con_Url *url_con, | ||
439 | void *data) | ||
440 | { | ||
441 | #ifdef HAVE_CURL | ||
442 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
443 | { | ||
444 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_set"); | ||
445 | return; | ||
446 | } | ||
447 | |||
448 | url_con->data = data; | ||
449 | #else | ||
450 | return; | ||
451 | url_con = NULL; | ||
452 | data = NULL; | ||
453 | #endif | ||
454 | } | ||
455 | |||
456 | EAPI void | ||
457 | ecore_con_url_additional_header_add(Ecore_Con_Url *url_con, | ||
458 | const char *key, | ||
459 | const char *value) | ||
460 | { | ||
461 | #ifdef HAVE_CURL | ||
462 | char *tmp; | ||
463 | |||
464 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
465 | { | ||
466 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
467 | "ecore_con_url_additional_header_add"); | ||
468 | return; | ||
469 | } | ||
470 | |||
471 | tmp = malloc(strlen(key) + strlen(value) + 3); | ||
472 | if (!tmp) | ||
473 | return; | ||
474 | |||
475 | sprintf(tmp, "%s: %s", key, value); | ||
476 | url_con->additional_headers = eina_list_append(url_con->additional_headers, | ||
477 | tmp); | ||
478 | #else | ||
479 | return; | ||
480 | url_con = NULL; | ||
481 | key = NULL; | ||
482 | value = NULL; | ||
483 | #endif | ||
484 | } | ||
485 | |||
486 | EAPI void | ||
487 | ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con) | ||
488 | { | ||
489 | #ifdef HAVE_CURL | ||
490 | char *s; | ||
491 | |||
492 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
493 | { | ||
494 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
495 | "ecore_con_url_additional_headers_clear"); | ||
496 | return; | ||
497 | } | ||
498 | |||
499 | EINA_LIST_FREE(url_con->additional_headers, s) | ||
500 | free(s); | ||
501 | #else | ||
502 | return; | ||
503 | url_con = NULL; | ||
504 | #endif | ||
505 | } | ||
506 | |||
507 | EAPI void * | ||
508 | ecore_con_url_data_get(Ecore_Con_Url *url_con) | ||
509 | { | ||
510 | #ifdef HAVE_CURL | ||
511 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
512 | { | ||
513 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_get"); | ||
514 | return NULL; | ||
515 | } | ||
516 | |||
517 | return url_con->data; | ||
518 | #else | ||
519 | return NULL; | ||
520 | url_con = NULL; | ||
521 | #endif | ||
522 | } | ||
523 | |||
524 | EAPI void | ||
525 | ecore_con_url_time(Ecore_Con_Url *url_con, | ||
526 | Ecore_Con_Url_Time condition, | ||
527 | double timestamp) | ||
528 | { | ||
529 | #ifdef HAVE_CURL | ||
530 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
531 | { | ||
532 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_time"); | ||
533 | return; | ||
534 | } | ||
535 | |||
536 | url_con->time_condition = condition; | ||
537 | url_con->timestamp = timestamp; | ||
538 | #else | ||
539 | return; | ||
540 | (void)url_con; | ||
541 | (void)condition; | ||
542 | (void)timestamp; | ||
543 | #endif | ||
544 | } | ||
545 | |||
546 | EAPI void | ||
547 | ecore_con_url_fd_set(Ecore_Con_Url *url_con, | ||
548 | int fd) | ||
549 | { | ||
550 | #ifdef HAVE_CURL | ||
551 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
552 | { | ||
553 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_set"); | ||
554 | return; | ||
555 | } | ||
556 | |||
557 | url_con->write_fd = fd; | ||
558 | #else | ||
559 | return; | ||
560 | (void)url_con; | ||
561 | (void)fd; | ||
562 | #endif | ||
563 | } | ||
564 | |||
565 | EAPI int | ||
566 | ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con) | ||
567 | { | ||
568 | #ifdef HAVE_CURL | ||
569 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
570 | { | ||
571 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
572 | "ecore_con_url_received_bytes_get"); | ||
573 | return -1; | ||
574 | } | ||
575 | |||
576 | return url_con->received; | ||
577 | #else | ||
578 | return 0; | ||
579 | (void)url_con; | ||
580 | #endif | ||
581 | } | ||
582 | |||
583 | EAPI const Eina_List * | ||
584 | ecore_con_url_response_headers_get(Ecore_Con_Url *url_con) | ||
585 | { | ||
586 | #ifdef HAVE_CURL | ||
587 | return url_con->response_headers; | ||
588 | #else | ||
589 | return NULL; | ||
590 | (void)url_con; | ||
591 | #endif | ||
592 | } | ||
593 | |||
594 | EAPI Eina_Bool | ||
595 | ecore_con_url_httpauth_set(Ecore_Con_Url *url_con, | ||
596 | const char *username, | ||
597 | const char *password, | ||
598 | Eina_Bool safe) | ||
599 | { | ||
600 | #ifdef HAVE_CURL | ||
601 | CURLcode ret; | ||
602 | |||
603 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
604 | { | ||
605 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
606 | "ecore_con_url_httpauth_set"); | ||
607 | return EINA_FALSE; | ||
608 | } | ||
609 | |||
610 | # if LIBCURL_VERSION_NUM >= 0x071301 | ||
611 | if ((username) && (password)) | ||
612 | { | ||
613 | if (safe) | ||
614 | curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, | ||
615 | CURLAUTH_ANYSAFE); | ||
616 | else | ||
617 | curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY); | ||
618 | |||
619 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username); | ||
620 | if (ret != CURLE_OK) | ||
621 | { | ||
622 | ERR("Could not set username for HTTP authentication: %s", | ||
623 | curl_easy_strerror(ret)); | ||
624 | return EINA_FALSE; | ||
625 | } | ||
626 | |||
627 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password); | ||
628 | if (ret != CURLE_OK) | ||
629 | { | ||
630 | ERR("Could not set password for HTTP authentication: %s", | ||
631 | curl_easy_strerror(ret)); | ||
632 | return EINA_FALSE; | ||
633 | } | ||
634 | |||
635 | return EINA_TRUE; | ||
636 | } | ||
637 | # endif | ||
638 | #else | ||
639 | return EINA_FALSE; | ||
640 | (void)url_con; | ||
641 | (void)username; | ||
642 | (void)password; | ||
643 | (void)safe; | ||
644 | #endif | ||
645 | |||
646 | return EINA_FALSE; | ||
647 | } | ||
648 | |||
649 | #define MODE_AUTO 0 | ||
650 | #define MODE_GET 1 | ||
651 | #define MODE_POST 2 | ||
652 | |||
653 | static Eina_Bool | ||
654 | _ecore_con_url_send(Ecore_Con_Url *url_con, | ||
655 | int mode, | ||
656 | const void *data, | ||
657 | long length, | ||
658 | const char *content_type) | ||
659 | { | ||
660 | #ifdef HAVE_CURL | ||
661 | Eina_List *l; | ||
662 | const char *s; | ||
663 | char tmp[256]; | ||
664 | |||
665 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
666 | { | ||
667 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_send"); | ||
668 | return EINA_FALSE; | ||
669 | } | ||
670 | |||
671 | if (url_con->active) | ||
672 | return EINA_FALSE; | ||
673 | |||
674 | if (!url_con->url) | ||
675 | return EINA_FALSE; | ||
676 | |||
677 | /* Free response headers from previous send() calls */ | ||
678 | EINA_LIST_FREE(url_con->response_headers, s) | ||
679 | free((char *)s); | ||
680 | url_con->response_headers = NULL; | ||
681 | |||
682 | curl_slist_free_all(url_con->headers); | ||
683 | url_con->headers = NULL; | ||
684 | |||
685 | if ((mode == MODE_POST) || (mode == MODE_AUTO)) | ||
686 | { | ||
687 | if (data) | ||
688 | { | ||
689 | if ((content_type) && (strlen(content_type) < 200)) | ||
690 | { | ||
691 | snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type); | ||
692 | url_con->headers = curl_slist_append(url_con->headers, tmp); | ||
693 | } | ||
694 | |||
695 | curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, data); | ||
696 | curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length); | ||
697 | } | ||
698 | else curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, 0); | ||
699 | if (mode == MODE_POST) | ||
700 | curl_easy_setopt(url_con->curl_easy, CURLOPT_POST, 1); | ||
701 | } | ||
702 | |||
703 | switch (url_con->time_condition) | ||
704 | { | ||
705 | case ECORE_CON_URL_TIME_NONE: | ||
706 | curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, | ||
707 | CURL_TIMECOND_NONE); | ||
708 | break; | ||
709 | |||
710 | case ECORE_CON_URL_TIME_IFMODSINCE: | ||
711 | curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, | ||
712 | CURL_TIMECOND_IFMODSINCE); | ||
713 | curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE, | ||
714 | (long)url_con->timestamp); | ||
715 | break; | ||
716 | |||
717 | case ECORE_CON_URL_TIME_IFUNMODSINCE: | ||
718 | curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION, | ||
719 | CURL_TIMECOND_IFUNMODSINCE); | ||
720 | curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMEVALUE, | ||
721 | (long)url_con->timestamp); | ||
722 | break; | ||
723 | } | ||
724 | |||
725 | /* Additional headers */ | ||
726 | EINA_LIST_FOREACH(url_con->additional_headers, l, s) | ||
727 | url_con->headers = curl_slist_append(url_con->headers, s); | ||
728 | |||
729 | curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPHEADER, url_con->headers); | ||
730 | |||
731 | url_con->received = 0; | ||
732 | |||
733 | return _ecore_con_url_perform(url_con); | ||
734 | #else | ||
735 | return EINA_FALSE; | ||
736 | (void)url_con; | ||
737 | (void)mode; | ||
738 | (void)data; | ||
739 | (void)length; | ||
740 | (void)content_type; | ||
741 | #endif | ||
742 | } | ||
743 | |||
744 | EINA_DEPRECATED EAPI Eina_Bool | ||
745 | ecore_con_url_send(Ecore_Con_Url *url_con, | ||
746 | const void *data, | ||
747 | long length, | ||
748 | const char *content_type) | ||
749 | { | ||
750 | return _ecore_con_url_send(url_con, MODE_AUTO, data, length, content_type); | ||
751 | } | ||
752 | |||
753 | EAPI Eina_Bool | ||
754 | ecore_con_url_get(Ecore_Con_Url *url_con) | ||
755 | { | ||
756 | return _ecore_con_url_send(url_con, MODE_GET, NULL, 0, NULL); | ||
757 | } | ||
758 | |||
759 | EAPI Eina_Bool | ||
760 | ecore_con_url_post(Ecore_Con_Url *url_con, | ||
761 | const void *data, | ||
762 | long length, | ||
763 | const char *content_type) | ||
764 | { | ||
765 | return _ecore_con_url_send(url_con, MODE_POST, data, length, content_type); | ||
766 | } | ||
767 | |||
768 | EAPI Eina_Bool | ||
769 | ecore_con_url_ftp_upload(Ecore_Con_Url *url_con, | ||
770 | const char *filename, | ||
771 | const char *user, | ||
772 | const char *pass, | ||
773 | const char *upload_dir) | ||
774 | { | ||
775 | #ifdef HAVE_CURL | ||
776 | char url[4096]; | ||
777 | char userpwd[4096]; | ||
778 | FILE *fd; | ||
779 | struct stat file_info; | ||
780 | CURLcode ret; | ||
781 | |||
782 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
783 | { | ||
784 | ECORE_MAGIC_FAIL(url_con, | ||
785 | ECORE_MAGIC_CON_URL, | ||
786 | "ecore_con_url_ftp_upload"); | ||
787 | return EINA_FALSE; | ||
788 | } | ||
789 | |||
790 | if (url_con->active) | ||
791 | return EINA_FALSE; | ||
792 | |||
793 | if (!url_con->url) | ||
794 | return EINA_FALSE; | ||
795 | |||
796 | if (filename) | ||
797 | { | ||
798 | if (stat(filename, &file_info)) | ||
799 | return EINA_FALSE; | ||
800 | |||
801 | snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass); | ||
802 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERPWD, userpwd); | ||
803 | if (ret != CURLE_OK) | ||
804 | { | ||
805 | ERR("Could not set username and password for FTP upload: %s", | ||
806 | curl_easy_strerror(ret)); | ||
807 | return EINA_FALSE; | ||
808 | } | ||
809 | |||
810 | char tmp[PATH_MAX]; | ||
811 | snprintf(tmp, PATH_MAX, "%s", filename); | ||
812 | |||
813 | if (upload_dir) | ||
814 | snprintf(url, sizeof(url), "ftp://%s/%s/%s", url_con->url, | ||
815 | upload_dir, basename(tmp)); | ||
816 | else | ||
817 | snprintf(url, sizeof(url), "ftp://%s/%s", url_con->url, | ||
818 | basename(tmp)); | ||
819 | |||
820 | if (!ecore_con_url_url_set(url_con, url)) | ||
821 | return EINA_FALSE; | ||
822 | |||
823 | curl_easy_setopt(url_con->curl_easy, CURLOPT_INFILESIZE_LARGE, | ||
824 | (curl_off_t)file_info.st_size); | ||
825 | curl_easy_setopt(url_con->curl_easy, CURLOPT_UPLOAD, 1); | ||
826 | curl_easy_setopt(url_con->curl_easy, CURLOPT_READFUNCTION, | ||
827 | _ecore_con_url_read_cb); | ||
828 | |||
829 | fd = fopen(filename, "rb"); | ||
830 | if (!fd) | ||
831 | { | ||
832 | ERR("Could not open \"%s\" for FTP upload", filename); | ||
833 | return EINA_FALSE; | ||
834 | } | ||
835 | curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd); | ||
836 | |||
837 | return _ecore_con_url_perform(url_con); | ||
838 | } | ||
839 | #else | ||
840 | return EINA_FALSE; | ||
841 | (void)url_con; | ||
842 | (void)filename; | ||
843 | (void)user; | ||
844 | (void)pass; | ||
845 | (void)upload_dir; | ||
846 | #endif | ||
847 | |||
848 | return EINA_FALSE; | ||
849 | } | ||
850 | |||
851 | EAPI void | ||
852 | ecore_con_url_cookies_init(Ecore_Con_Url *url_con) | ||
853 | { | ||
854 | #ifdef HAVE_CURL | ||
855 | if (!url_con) | ||
856 | return; | ||
857 | |||
858 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
859 | { | ||
860 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
861 | "ecore_con_url_cookies_init"); | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, ""); | ||
866 | #else | ||
867 | return; | ||
868 | (void)url_con; | ||
869 | #endif | ||
870 | } | ||
871 | |||
872 | EAPI void | ||
873 | ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, Eina_Bool ignore) | ||
874 | { | ||
875 | #ifdef HAVE_CURL | ||
876 | if (!url_con) | ||
877 | return; | ||
878 | |||
879 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
880 | { | ||
881 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
882 | "ecore_con_url_cookies_ignore_old_session_set"); | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIESESSION, ignore); | ||
887 | #else | ||
888 | return; | ||
889 | (void)url_con; | ||
890 | (void)ignore; | ||
891 | #endif | ||
892 | } | ||
893 | |||
894 | EAPI void | ||
895 | ecore_con_url_cookies_clear(Ecore_Con_Url *url_con) | ||
896 | { | ||
897 | #ifdef HAVE_CURL | ||
898 | if (!url_con) | ||
899 | return; | ||
900 | |||
901 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
902 | { | ||
903 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
904 | "ecore_con_url_cookies_clear"); | ||
905 | return; | ||
906 | } | ||
907 | |||
908 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "ALL"); | ||
909 | #else | ||
910 | return; | ||
911 | (void)url_con; | ||
912 | #endif | ||
913 | } | ||
914 | |||
915 | EAPI void | ||
916 | ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con) | ||
917 | { | ||
918 | #ifdef HAVE_CURL | ||
919 | if (!url_con) | ||
920 | return; | ||
921 | |||
922 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
923 | { | ||
924 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
925 | "ecore_con_url_cookies_session_clear"); | ||
926 | return; | ||
927 | } | ||
928 | |||
929 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "SESS"); | ||
930 | #else | ||
931 | return; | ||
932 | (void)url_con; | ||
933 | #endif | ||
934 | } | ||
935 | |||
936 | EAPI void | ||
937 | ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, const char * const file_name) | ||
938 | { | ||
939 | #ifdef HAVE_CURL | ||
940 | if (!url_con) | ||
941 | return; | ||
942 | |||
943 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
944 | { | ||
945 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
946 | "ecore_con_url_cookies_file_add"); | ||
947 | return; | ||
948 | } | ||
949 | |||
950 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, file_name); | ||
951 | #else | ||
952 | return; | ||
953 | (void)url_con; | ||
954 | (void)file_name; | ||
955 | #endif | ||
956 | } | ||
957 | |||
958 | EAPI Eina_Bool | ||
959 | ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, const char * const cookiejar_file) | ||
960 | { | ||
961 | #ifdef HAVE_CURL | ||
962 | CURLcode ret; | ||
963 | |||
964 | if (!url_con) | ||
965 | return EINA_FALSE; | ||
966 | |||
967 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
968 | { | ||
969 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
970 | "ecore_con_url_cookies_jar_file_set"); | ||
971 | return EINA_FALSE; | ||
972 | } | ||
973 | |||
974 | ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEJAR, | ||
975 | cookiejar_file); | ||
976 | if (ret != CURLE_OK) | ||
977 | { | ||
978 | ERR("Setting the cookie-jar name failed: %s", | ||
979 | curl_easy_strerror(ret)); | ||
980 | return EINA_FALSE; | ||
981 | } | ||
982 | |||
983 | return EINA_TRUE; | ||
984 | #else | ||
985 | return EINA_FALSE; | ||
986 | (void)url_con; | ||
987 | (void)cookiejar_file; | ||
988 | #endif | ||
989 | } | ||
990 | |||
991 | EAPI void | ||
992 | ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con) | ||
993 | { | ||
994 | #ifdef HAVE_CURL | ||
995 | if (!url_con) | ||
996 | return; | ||
997 | |||
998 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
999 | { | ||
1000 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
1001 | "ecore_con_url_cookies_jar_write"); | ||
1002 | return; | ||
1003 | } | ||
1004 | |||
1005 | curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "FLUSH"); | ||
1006 | #else | ||
1007 | return; | ||
1008 | (void)url_con; | ||
1009 | #endif | ||
1010 | } | ||
1011 | |||
1012 | EAPI void | ||
1013 | ecore_con_url_verbose_set(Ecore_Con_Url *url_con, | ||
1014 | Eina_Bool verbose) | ||
1015 | { | ||
1016 | #ifdef HAVE_CURL | ||
1017 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
1018 | { | ||
1019 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
1020 | "ecore_con_url_verbose_set"); | ||
1021 | return; | ||
1022 | } | ||
1023 | |||
1024 | if (url_con->active) | ||
1025 | return; | ||
1026 | |||
1027 | if (!url_con->url) | ||
1028 | return; | ||
1029 | |||
1030 | curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, (int)verbose); | ||
1031 | #else | ||
1032 | return; | ||
1033 | (void)url_con; | ||
1034 | (void)verbose; | ||
1035 | #endif | ||
1036 | } | ||
1037 | |||
1038 | EAPI void | ||
1039 | ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con, | ||
1040 | Eina_Bool use_epsv) | ||
1041 | { | ||
1042 | #ifdef HAVE_CURL | ||
1043 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
1044 | { | ||
1045 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
1046 | "ecore_con_url_ftp_use_epsv_set"); | ||
1047 | return; | ||
1048 | } | ||
1049 | |||
1050 | if (url_con->active) | ||
1051 | return; | ||
1052 | |||
1053 | if (!url_con->url) | ||
1054 | return; | ||
1055 | |||
1056 | curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, (int)use_epsv); | ||
1057 | #else | ||
1058 | return; | ||
1059 | (void)url_con; | ||
1060 | (void)use_epsv; | ||
1061 | #endif | ||
1062 | } | ||
1063 | |||
1064 | /** | ||
1065 | * Toggle libcurl's verify peer's certificate option. | ||
1066 | * | ||
1067 | * If @p verify is @c EINA_TRUE, libcurl will verify | ||
1068 | * the authenticity of the peer's certificate, otherwise | ||
1069 | * it will not. Default behavior of libcurl is to check | ||
1070 | * peer's certificate. | ||
1071 | * | ||
1072 | * @param url_con Ecore_Con_Url instance which will be acted upon. | ||
1073 | * @param verify Whether or not libcurl will check peer's certificate. | ||
1074 | * @since 1.1.0 | ||
1075 | */ | ||
1076 | EAPI void | ||
1077 | ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con, | ||
1078 | Eina_Bool verify) | ||
1079 | { | ||
1080 | #ifdef HAVE_CURL | ||
1081 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
1082 | { | ||
1083 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, | ||
1084 | "ecore_con_url_ssl_verify_peer_set"); | ||
1085 | return; | ||
1086 | } | ||
1087 | |||
1088 | if (url_con->active) | ||
1089 | return; | ||
1090 | |||
1091 | if (!url_con->url) | ||
1092 | return; | ||
1093 | |||
1094 | curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, (int)verify); | ||
1095 | #else | ||
1096 | return; | ||
1097 | (void)url_con; | ||
1098 | (void)verify; | ||
1099 | #endif | ||
1100 | } | ||
1101 | |||
1102 | /** | ||
1103 | * Set a custom CA to trust for SSL/TLS connections. | ||
1104 | * | ||
1105 | * Specify the path of a file (in PEM format) containing one or more | ||
1106 | * CA certificate(s) to use for the validation of the server certificate. | ||
1107 | * | ||
1108 | * This function can also disable CA validation if @p ca_path is @c NULL. | ||
1109 | * However, the server certificate still needs to be valid for the connection | ||
1110 | * to succeed (i.e., the certificate must concern the server the | ||
1111 | * connection is made to). | ||
1112 | * | ||
1113 | * @param url_con Connection object that will use the custom CA. | ||
1114 | * @param ca_path Path to a CA certificate(s) file or @c NULL to disable | ||
1115 | * CA validation. | ||
1116 | * | ||
1117 | * @return @c 0 on success. When cURL is used, non-zero return values | ||
1118 | * are equal to cURL error codes. | ||
1119 | */ | ||
1120 | EAPI int | ||
1121 | ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path) | ||
1122 | { | ||
1123 | int res = -1; | ||
1124 | |||
1125 | #ifdef HAVE_CURL | ||
1126 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
1127 | { | ||
1128 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_ssl_ca_set"); | ||
1129 | return -1; | ||
1130 | } | ||
1131 | |||
1132 | if (url_con->active) return -1; | ||
1133 | if (!url_con->url) return -1; | ||
1134 | if (ca_path == NULL) | ||
1135 | res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0); | ||
1136 | else | ||
1137 | { | ||
1138 | res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 1); | ||
1139 | if (!res) | ||
1140 | res = curl_easy_setopt(url_con->curl_easy, CURLOPT_CAINFO, ca_path); | ||
1141 | } | ||
1142 | #else | ||
1143 | return -1; | ||
1144 | (void)url_con; | ||
1145 | (void)ca_path; | ||
1146 | #endif | ||
1147 | |||
1148 | return res; | ||
1149 | } | ||
1150 | |||
1151 | |||
1152 | /** | ||
1153 | * @} | ||
1154 | */ | ||
1155 | |||
1156 | #ifdef HAVE_CURL | ||
1157 | static int | ||
1158 | _ecore_con_url_suspend_fd_handler(void) | ||
1159 | { | ||
1160 | Eina_List *l; | ||
1161 | Ecore_Con_Url *url_con; | ||
1162 | int deleted = 0; | ||
1163 | |||
1164 | if (!_url_con_list) | ||
1165 | return 0; | ||
1166 | |||
1167 | EINA_LIST_FOREACH(_url_con_list, l, url_con) | ||
1168 | { | ||
1169 | if (url_con->active && url_con->fd_handler) | ||
1170 | { | ||
1171 | ecore_main_fd_handler_del(url_con->fd_handler); | ||
1172 | url_con->fd_handler = NULL; | ||
1173 | deleted++; | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | return deleted; | ||
1178 | } | ||
1179 | |||
1180 | static int | ||
1181 | _ecore_con_url_restart_fd_handler(void) | ||
1182 | { | ||
1183 | Eina_List *l; | ||
1184 | Ecore_Con_Url *url_con; | ||
1185 | int activated = 0; | ||
1186 | |||
1187 | if (!_url_con_list) | ||
1188 | return 0; | ||
1189 | |||
1190 | EINA_LIST_FOREACH(_url_con_list, l, url_con) | ||
1191 | { | ||
1192 | if (!url_con->fd_handler && url_con->fd != -1) | ||
1193 | { | ||
1194 | url_con->fd_handler = | ||
1195 | ecore_main_fd_handler_add(url_con->fd, url_con->flags, | ||
1196 | _ecore_con_url_fd_handler, | ||
1197 | NULL, NULL, NULL); | ||
1198 | activated++; | ||
1199 | } | ||
1200 | } | ||
1201 | |||
1202 | return activated; | ||
1203 | } | ||
1204 | |||
1205 | static size_t | ||
1206 | _ecore_con_url_data_cb(void *buffer, | ||
1207 | size_t size, | ||
1208 | size_t nitems, | ||
1209 | void *userp) | ||
1210 | { | ||
1211 | Ecore_Con_Url *url_con; | ||
1212 | Ecore_Con_Event_Url_Data *e; | ||
1213 | size_t real_size = size * nitems; | ||
1214 | |||
1215 | url_con = (Ecore_Con_Url *)userp; | ||
1216 | |||
1217 | if (!url_con) | ||
1218 | return -1; | ||
1219 | |||
1220 | if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) | ||
1221 | { | ||
1222 | ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_cb"); | ||
1223 | return -1; | ||
1224 | } | ||
1225 | |||
1226 | url_con->received += real_size; | ||
1227 | |||
1228 | if (url_con->write_fd < 0) | ||
1229 | { | ||
1230 | e = | ||
1231 | malloc(sizeof(Ecore_Con_Event_Url_Data) + sizeof(unsigned char) * | ||
1232 | (real_size - 1)); | ||
1233 | if (e) | ||
1234 | { | ||
1235 | e->url_con = url_con; | ||
1236 | e->size = real_size; | ||
1237 | memcpy(e->data, buffer, real_size); | ||
1238 | ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, | ||
1239 | _ecore_con_event_url_free, NULL); | ||
1240 | } | ||
1241 | } | ||
1242 | else | ||
1243 | { | ||
1244 | ssize_t count = 0; | ||
1245 | size_t total_size = real_size; | ||
1246 | size_t offset = 0; | ||
1247 | |||
1248 | while (total_size > 0) | ||
1249 | { | ||
1250 | count = write(url_con->write_fd, | ||
1251 | (char *)buffer + offset, | ||
1252 | total_size); | ||
1253 | if (count < 0) | ||
1254 | { | ||
1255 | if (errno != EAGAIN && errno != EINTR) | ||
1256 | return -1; | ||
1257 | } | ||
1258 | else | ||
1259 | { | ||
1260 | total_size -= count; | ||
1261 | offset += count; | ||
1262 | } | ||
1263 | } | ||
1264 | } | ||
1265 | |||
1266 | return real_size; | ||
1267 | } | ||
1268 | |||
1269 | #define ECORE_CON_URL_TRANSMISSION(Transmit, Event, Url_con, Total, Now) \ | ||
1270 | { \ | ||
1271 | Ecore_Con_Event_Url_Progress *e; \ | ||
1272 | if ((Total != 0) || (Now != 0)) \ | ||
1273 | { \ | ||
1274 | e = calloc(1, sizeof(Ecore_Con_Event_Url_Progress)); \ | ||
1275 | if (e) \ | ||
1276 | { \ | ||
1277 | e->url_con = url_con; \ | ||
1278 | e->total = Total; \ | ||
1279 | e->now = Now; \ | ||
1280 | ecore_event_add(Event, e, _ecore_con_event_url_free, NULL); \ | ||
1281 | } \ | ||
1282 | } \ | ||
1283 | } | ||
1284 | |||
1285 | static size_t | ||
1286 | _ecore_con_url_header_cb(void *ptr, | ||
1287 | size_t size, | ||
1288 | size_t nitems, | ||
1289 | void *stream) | ||
1290 | { | ||
1291 | size_t real_size = size * nitems; | ||
1292 | Ecore_Con_Url *url_con = stream; | ||
1293 | |||
1294 | char *header = malloc(sizeof(char) * (real_size + 1)); | ||
1295 | if (!header) | ||
1296 | return real_size; | ||
1297 | |||
1298 | memcpy(header, ptr, real_size); | ||
1299 | header[real_size] = '\0'; | ||
1300 | |||
1301 | url_con->response_headers = eina_list_append(url_con->response_headers, | ||
1302 | header); | ||
1303 | |||
1304 | return real_size; | ||
1305 | } | ||
1306 | |||
1307 | static int | ||
1308 | _ecore_con_url_progress_cb(void *clientp, | ||
1309 | double dltotal, | ||
1310 | double dlnow, | ||
1311 | double ultotal, | ||
1312 | double ulnow) | ||
1313 | { | ||
1314 | Ecore_Con_Event_Url_Progress *e; | ||
1315 | Ecore_Con_Url *url_con; | ||
1316 | |||
1317 | url_con = clientp; | ||
1318 | |||
1319 | e = malloc(sizeof(Ecore_Con_Event_Url_Progress)); | ||
1320 | if (e) | ||
1321 | { | ||
1322 | e->url_con = url_con; | ||
1323 | e->down.total = dltotal; | ||
1324 | e->down.now = dlnow; | ||
1325 | e->up.total = ultotal; | ||
1326 | e->up.now = ulnow; | ||
1327 | ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, | ||
1328 | _ecore_con_event_url_free, NULL); | ||
1329 | } | ||
1330 | |||
1331 | return 0; | ||
1332 | } | ||
1333 | |||
1334 | static size_t | ||
1335 | _ecore_con_url_read_cb(void *ptr, | ||
1336 | size_t size, | ||
1337 | size_t nitems, | ||
1338 | void *stream) | ||
1339 | { | ||
1340 | size_t retcode = fread(ptr, size, nitems, stream); | ||
1341 | |||
1342 | if (ferror((FILE *)stream)) | ||
1343 | { | ||
1344 | fclose(stream); | ||
1345 | return CURL_READFUNC_ABORT; | ||
1346 | } | ||
1347 | else if (retcode == 0) | ||
1348 | { | ||
1349 | fclose((FILE *)stream); | ||
1350 | return 0; | ||
1351 | } | ||
1352 | |||
1353 | #ifdef _WIN32 | ||
1354 | INF("*** We read %Iu bytes from file", retcode); | ||
1355 | #else | ||
1356 | INF("*** We read %zu bytes from file", retcode); | ||
1357 | #endif | ||
1358 | return retcode; | ||
1359 | } | ||
1360 | |||
1361 | static Eina_Bool | ||
1362 | _ecore_con_url_perform(Ecore_Con_Url *url_con) | ||
1363 | { | ||
1364 | fd_set read_set, write_set, exc_set; | ||
1365 | int fd_max, fd; | ||
1366 | int flags, still_running; | ||
1367 | int completed_immediately = 0; | ||
1368 | CURLMcode ret; | ||
1369 | |||
1370 | _url_con_list = eina_list_append(_url_con_list, url_con); | ||
1371 | |||
1372 | url_con->active = EINA_TRUE; | ||
1373 | curl_multi_add_handle(_curlm, url_con->curl_easy); | ||
1374 | curl_multi_perform(_curlm, &still_running); | ||
1375 | |||
1376 | completed_immediately = _ecore_con_url_process_completed_jobs(url_con); | ||
1377 | |||
1378 | if (!completed_immediately) | ||
1379 | { | ||
1380 | if (url_con->fd_handler) | ||
1381 | ecore_main_fd_handler_del(url_con->fd_handler); | ||
1382 | |||
1383 | url_con->fd_handler = NULL; | ||
1384 | |||
1385 | /* url_con still active -- set up an fd_handler */ | ||
1386 | FD_ZERO(&read_set); | ||
1387 | FD_ZERO(&write_set); | ||
1388 | FD_ZERO(&exc_set); | ||
1389 | |||
1390 | /* Stupid curl, why can't I get the fd to the current added job? */ | ||
1391 | ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, | ||
1392 | &fd_max); | ||
1393 | if (ret != CURLM_OK) | ||
1394 | { | ||
1395 | ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret)); | ||
1396 | return EINA_FALSE; | ||
1397 | } | ||
1398 | |||
1399 | for (fd = 0; fd <= fd_max; fd++) | ||
1400 | { | ||
1401 | if (!FD_ISSET(fd, &_current_fd_set)) | ||
1402 | { | ||
1403 | flags = 0; | ||
1404 | if (FD_ISSET(fd, &read_set)) | ||
1405 | flags |= ECORE_FD_READ; | ||
1406 | |||
1407 | if (FD_ISSET(fd, &write_set)) | ||
1408 | flags |= ECORE_FD_WRITE; | ||
1409 | |||
1410 | if (FD_ISSET(fd, &exc_set)) | ||
1411 | flags |= ECORE_FD_ERROR; | ||
1412 | |||
1413 | if (flags) | ||
1414 | { | ||
1415 | long ms = 0; | ||
1416 | |||
1417 | ret = curl_multi_timeout(_curlm, &ms); | ||
1418 | if (ret != CURLM_OK) | ||
1419 | ERR("curl_multi_timeout failed: %s", | ||
1420 | curl_multi_strerror(ret)); | ||
1421 | |||
1422 | if (ms == 0) | ||
1423 | ms = 1000; | ||
1424 | |||
1425 | FD_SET(fd, &_current_fd_set); | ||
1426 | url_con->fd = fd; | ||
1427 | url_con->flags = flags; | ||
1428 | url_con->fd_handler = | ||
1429 | ecore_main_fd_handler_add(fd, flags, | ||
1430 | _ecore_con_url_fd_handler, | ||
1431 | NULL, NULL, NULL); | ||
1432 | break; | ||
1433 | } | ||
1434 | } | ||
1435 | } | ||
1436 | if (!url_con->fd_handler) | ||
1437 | { | ||
1438 | /* Failed to set up an fd_handler */ | ||
1439 | ecore_timer_freeze(_curl_timeout); | ||
1440 | |||
1441 | ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); | ||
1442 | if (ret != CURLM_OK) | ||
1443 | ERR("curl_multi_remove_handle failed: %s", | ||
1444 | curl_multi_strerror(ret)); | ||
1445 | |||
1446 | url_con->active = EINA_FALSE; | ||
1447 | url_con->fd = -1; | ||
1448 | return EINA_FALSE; | ||
1449 | } | ||
1450 | |||
1451 | ecore_timer_thaw(_curl_timeout); | ||
1452 | } | ||
1453 | |||
1454 | return EINA_TRUE; | ||
1455 | } | ||
1456 | |||
1457 | static Eina_Bool | ||
1458 | _ecore_con_url_idler_handler(void *data) | ||
1459 | { | ||
1460 | int done, still_running; | ||
1461 | |||
1462 | done = (curl_multi_perform(_curlm, &still_running) != CURLM_CALL_MULTI_PERFORM); | ||
1463 | |||
1464 | _ecore_con_url_process_completed_jobs(NULL); | ||
1465 | |||
1466 | if (done) | ||
1467 | { | ||
1468 | _ecore_con_url_restart_fd_handler(); | ||
1469 | _fd_idler_handler = NULL; | ||
1470 | |||
1471 | if (!_url_con_list) | ||
1472 | ecore_timer_freeze(_curl_timeout); | ||
1473 | |||
1474 | return data == | ||
1475 | (void *)0xACE ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL; | ||
1476 | } | ||
1477 | |||
1478 | return ECORE_CALLBACK_RENEW; | ||
1479 | } | ||
1480 | |||
1481 | static Eina_Bool | ||
1482 | _ecore_con_url_fd_handler(void *data __UNUSED__, | ||
1483 | Ecore_Fd_Handler *fd_handler __UNUSED__) | ||
1484 | { | ||
1485 | _ecore_con_url_suspend_fd_handler(); | ||
1486 | |||
1487 | if (!_fd_idler_handler) | ||
1488 | _fd_idler_handler = ecore_idler_add( | ||
1489 | _ecore_con_url_idler_handler, NULL); | ||
1490 | |||
1491 | return ECORE_CALLBACK_RENEW; | ||
1492 | } | ||
1493 | |||
1494 | static int | ||
1495 | _ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match) | ||
1496 | { | ||
1497 | Eina_List *l; | ||
1498 | Ecore_Con_Url *url_con; | ||
1499 | Ecore_Con_Event_Url_Complete *e; | ||
1500 | CURLMsg *curlmsg; | ||
1501 | CURLMcode ret; | ||
1502 | int n_remaining; | ||
1503 | int job_matched = 0; | ||
1504 | |||
1505 | /* Loop jobs and check if any are done */ | ||
1506 | while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining))) | ||
1507 | { | ||
1508 | if (curlmsg->msg != CURLMSG_DONE) | ||
1509 | continue; | ||
1510 | |||
1511 | /* find the job which is done */ | ||
1512 | EINA_LIST_FOREACH(_url_con_list, l, url_con) | ||
1513 | { | ||
1514 | if (curlmsg->easy_handle == url_con->curl_easy) | ||
1515 | { | ||
1516 | if (url_con_to_match && | ||
1517 | (url_con == url_con_to_match)) | ||
1518 | job_matched = 1; | ||
1519 | |||
1520 | if(url_con->fd != -1) | ||
1521 | { | ||
1522 | FD_CLR(url_con->fd, &_current_fd_set); | ||
1523 | if (url_con->fd_handler) | ||
1524 | ecore_main_fd_handler_del( | ||
1525 | url_con->fd_handler); | ||
1526 | |||
1527 | url_con->fd = -1; | ||
1528 | url_con->fd_handler = NULL; | ||
1529 | } | ||
1530 | |||
1531 | _url_con_list = eina_list_remove(_url_con_list, url_con); | ||
1532 | url_con->active = EINA_FALSE; | ||
1533 | e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete)); | ||
1534 | if (e) | ||
1535 | { | ||
1536 | e->url_con = url_con; | ||
1537 | e->status = 0; | ||
1538 | if (curlmsg->data.result == CURLE_OK) | ||
1539 | { | ||
1540 | long status; /* curl API uses long, not int */ | ||
1541 | |||
1542 | status = 0; | ||
1543 | curl_easy_getinfo(curlmsg->easy_handle, | ||
1544 | CURLINFO_RESPONSE_CODE, | ||
1545 | &status); | ||
1546 | e->status = status; | ||
1547 | } | ||
1548 | |||
1549 | _url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e); | ||
1550 | } | ||
1551 | |||
1552 | ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); | ||
1553 | if (ret != CURLM_OK) | ||
1554 | ERR("curl_multi_remove_handle failed: %s", | ||
1555 | curl_multi_strerror(ret)); | ||
1556 | |||
1557 | break; | ||
1558 | } | ||
1559 | } | ||
1560 | } | ||
1561 | |||
1562 | return job_matched; | ||
1563 | } | ||
1564 | |||
1565 | static void | ||
1566 | _ecore_con_event_url_free(void *data __UNUSED__, | ||
1567 | void *ev) | ||
1568 | { | ||
1569 | free(ev); | ||
1570 | } | ||
1571 | |||
1572 | #endif | ||