2 * For info on how to use libcurl, see:
3 * http://curl.haxx.se/libcurl/c/libcurl-tutorial.html
7 * FIXME: Support more CURL features...
17 #include <sys/types.h>
20 #ifdef HAVE_WS2TCPIP_H
21 # include <ws2tcpip.h>
25 #include "ecore_private.h"
26 #include "Ecore_Con.h"
27 #include "ecore_con_private.h"
29 int ECORE_CON_EVENT_URL_DATA = 0;
30 int ECORE_CON_EVENT_URL_COMPLETE = 0;
31 int ECORE_CON_EVENT_URL_PROGRESS = 0;
34 static Eina_Bool _ecore_con_url_fd_handler(void *data,
35 Ecore_Fd_Handler *fd_handler);
36 static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con);
37 static size_t _ecore_con_url_header_cb(void *ptr,
41 static size_t _ecore_con_url_data_cb(void *buffer,
45 static int _ecore_con_url_progress_cb(void *clientp,
50 static size_t _ecore_con_url_read_cb(void *ptr,
54 static void _ecore_con_event_url_free(void *data __UNUSED__,
56 static int _ecore_con_url_process_completed_jobs(
57 Ecore_Con_Url *url_con_to_match);
58 static Eina_Bool _ecore_con_url_idler_handler(void *data);
60 static Ecore_Idler *_fd_idler_handler = NULL;
61 static Eina_List *_url_con_list = NULL;
62 static CURLM *_curlm = NULL;
63 static fd_set _current_fd_set;
64 static int _init_count = 0;
65 static Ecore_Timer *_curl_timeout = NULL;
66 static Eina_Bool pipelining = EINA_FALSE;
68 typedef struct _Ecore_Con_Url_Event Ecore_Con_Url_Event;
69 struct _Ecore_Con_Url_Event
76 _url_complete_idler_cb(void *data)
78 Ecore_Con_Url_Event *lev;
81 ecore_event_add(lev->type, lev->ev, _ecore_con_event_url_free, NULL);
84 return ECORE_CALLBACK_CANCEL;
88 _url_complete_push_event(int type,
91 Ecore_Con_Url_Event *lev;
93 lev = malloc(sizeof(Ecore_Con_Url_Event));
97 ecore_idler_add(_url_complete_idler_cb, lev);
103 * @addtogroup Ecore_Con_Url_Group Ecore URL Connection Functions
109 ecore_con_url_init(void)
117 if (!ECORE_CON_EVENT_URL_DATA)
119 ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
120 ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new();
121 ECORE_CON_EVENT_URL_PROGRESS = ecore_event_type_new();
128 FD_ZERO(&_current_fd_set);
129 if (curl_global_init(CURL_GLOBAL_ALL))
131 while (_url_con_list)
132 ecore_con_url_free(eina_list_data_get(_url_con_list));
136 _curlm = curl_multi_init();
139 while (_url_con_list)
140 ecore_con_url_free(eina_list_data_get(_url_con_list));
146 curl_multi_timeout(_curlm, &ms);
151 ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler,
153 ecore_timer_freeze(_curl_timeout);
163 ecore_con_url_shutdown(void)
171 if (_init_count != 0)
174 if (_fd_idler_handler)
175 ecore_idler_del(_fd_idler_handler);
177 _fd_idler_handler = NULL;
180 ecore_timer_del(_curl_timeout);
182 _curl_timeout = NULL;
184 while (_url_con_list)
185 ecore_con_url_free(eina_list_data_get(_url_con_list));
189 curl_multi_cleanup(_curlm);
193 curl_global_cleanup();
199 ecore_con_url_pipeline_set(Eina_Bool enable)
203 curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, 1);
205 curl_multi_setopt(_curlm, CURLMOPT_PIPELINING, 0);
214 ecore_con_url_pipeline_get(void)
223 ecore_con_url_new(const char *url)
226 Ecore_Con_Url *url_con;
232 url_con = calloc(1, sizeof(Ecore_Con_Url));
237 url_con->write_fd = -1;
239 url_con->curl_easy = curl_easy_init();
240 if (!url_con->curl_easy)
246 ECORE_MAGIC_SET(url_con, ECORE_MAGIC_CON_URL);
248 if (!ecore_con_url_url_set(url_con, url))
250 ecore_con_url_free(url_con);
254 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate");
257 ERR("Could not set CURLOPT_ENCODING to \"gzip,deflate\": %s",
258 curl_easy_strerror(ret));
259 ecore_con_url_free(url_con);
263 curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEFUNCTION,
264 _ecore_con_url_data_cb);
265 curl_easy_setopt(url_con->curl_easy, CURLOPT_WRITEDATA, url_con);
267 curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION,
268 _ecore_con_url_progress_cb);
269 curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSDATA, url_con);
270 curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_FALSE);
272 curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERFUNCTION,
273 _ecore_con_url_header_cb);
274 curl_easy_setopt(url_con->curl_easy, CURLOPT_HEADERDATA, url_con);
277 * FIXME: Check that these timeouts are sensible defaults
278 * FIXME: Provide a means to change these timeouts
280 curl_easy_setopt(url_con->curl_easy, CURLOPT_MAXCONNECTS, 100);
281 curl_easy_setopt(url_con->curl_easy, CURLOPT_FORBID_REUSE, 1);
282 curl_easy_setopt(url_con->curl_easy, CURLOPT_CONNECTTIMEOUT, 30);
283 curl_easy_setopt(url_con->curl_easy, CURLOPT_FOLLOWLOCATION, 1);
293 ecore_con_url_custom_new(const char *url,
294 const char *custom_request)
297 Ecore_Con_Url *url_con;
306 url_con = ecore_con_url_new(url);
311 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_CUSTOMREQUEST, custom_request);
314 ERR("Could not set a custom request string: %s",
315 curl_easy_strerror(ret));
316 ecore_con_url_free(url_con);
324 custom_request = NULL;
329 ecore_con_url_free(Ecore_Con_Url *url_con)
338 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
340 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_free");
344 ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE);
345 if(url_con->fd != -1)
347 FD_CLR(url_con->fd, &_current_fd_set);
348 if (url_con->fd_handler)
349 ecore_main_fd_handler_del(url_con->fd_handler);
352 url_con->fd_handler = NULL;
355 if (url_con->curl_easy)
357 // FIXME: For an unknown reason, progress continue to arrive after destruction
358 // this prevent any further call to the callback.
359 curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE);
360 curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL);
361 curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE);
365 url_con->active = EINA_FALSE;
367 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
369 ERR("curl_multi_remove_handle failed: %s",
370 curl_multi_strerror(ret));
373 curl_easy_cleanup(url_con->curl_easy);
376 _url_con_list = eina_list_remove(_url_con_list, url_con);
377 curl_slist_free_all(url_con->headers);
378 EINA_LIST_FREE(url_con->additional_headers, s)
380 EINA_LIST_FREE(url_con->response_headers, s)
382 eina_stringshare_del(url_con->url);
391 ecore_con_url_url_get(Ecore_Con_Url *url_con)
394 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
396 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, __func__);
407 ecore_con_url_url_set(Ecore_Con_Url *url_con,
411 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
413 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_url_set");
420 eina_stringshare_replace(&url_con->url, url);
423 curl_easy_setopt(url_con->curl_easy, CURLOPT_URL,
426 curl_easy_setopt(url_con->curl_easy, CURLOPT_URL, "");
437 ecore_con_url_data_set(Ecore_Con_Url *url_con,
441 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
443 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_set");
447 url_con->data = data;
456 ecore_con_url_additional_header_add(Ecore_Con_Url *url_con,
463 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
465 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
466 "ecore_con_url_additional_header_add");
470 tmp = malloc(strlen(key) + strlen(value) + 3);
474 sprintf(tmp, "%s: %s", key, value);
475 url_con->additional_headers = eina_list_append(url_con->additional_headers,
486 ecore_con_url_additional_headers_clear(Ecore_Con_Url *url_con)
491 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
493 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
494 "ecore_con_url_additional_headers_clear");
498 EINA_LIST_FREE(url_con->additional_headers, s)
507 ecore_con_url_data_get(Ecore_Con_Url *url_con)
510 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
512 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_get");
516 return url_con->data;
524 ecore_con_url_time(Ecore_Con_Url *url_con,
525 Ecore_Con_Url_Time condition,
529 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
531 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_time");
535 url_con->time_condition = condition;
536 url_con->timestamp = timestamp;
546 ecore_con_url_fd_set(Ecore_Con_Url *url_con,
550 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
552 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_set");
556 url_con->write_fd = fd;
565 ecore_con_url_received_bytes_get(Ecore_Con_Url *url_con)
568 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
570 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
571 "ecore_con_url_received_bytes_get");
575 return url_con->received;
582 EAPI const Eina_List *
583 ecore_con_url_response_headers_get(Ecore_Con_Url *url_con)
586 return url_con->response_headers;
594 ecore_con_url_httpauth_set(Ecore_Con_Url *url_con,
595 const char *username,
596 const char *password,
602 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
604 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
605 "ecore_con_url_httpauth_set");
609 # if LIBCURL_VERSION_NUM >= 0x071301
610 if ((username) && (password))
613 curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH,
616 curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
618 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
621 ERR("Could not set username for HTTP authentication: %s",
622 curl_easy_strerror(ret));
626 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
629 ERR("Could not set password for HTTP authentication: %s",
630 curl_easy_strerror(ret));
653 _ecore_con_url_send(Ecore_Con_Url *url_con,
657 const char *content_type)
664 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
666 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_send");
676 /* Free response headers from previous send() calls */
677 EINA_LIST_FREE(url_con->response_headers, s)
679 url_con->response_headers = NULL;
681 curl_slist_free_all(url_con->headers);
682 url_con->headers = NULL;
684 if ((mode == MODE_POST) || (mode == MODE_AUTO))
688 if ((content_type) && (strlen(content_type) < 200))
690 snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type);
691 url_con->headers = curl_slist_append(url_con->headers, tmp);
694 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, data);
695 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length);
697 else if (mode == MODE_POST)
699 curl_easy_setopt(url_con->curl_easy, CURLOPT_POST, 1);
703 switch (url_con->time_condition)
705 case ECORE_CON_URL_TIME_NONE:
706 curl_easy_setopt(url_con->curl_easy, CURLOPT_TIMECONDITION,
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);
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);
725 /* Additional headers */
726 EINA_LIST_FOREACH(url_con->additional_headers, l, s)
727 url_con->headers = curl_slist_append(url_con->headers, s);
729 curl_easy_setopt(url_con->curl_easy, CURLOPT_HTTPHEADER, url_con->headers);
731 url_con->received = 0;
733 return _ecore_con_url_perform(url_con);
744 EINA_DEPRECATED EAPI Eina_Bool
745 ecore_con_url_send(Ecore_Con_Url *url_con,
748 const char *content_type)
750 return _ecore_con_url_send(url_con, MODE_AUTO, data, length, content_type);
754 ecore_con_url_get(Ecore_Con_Url *url_con)
756 return _ecore_con_url_send(url_con, MODE_GET, NULL, 0, NULL);
760 ecore_con_url_post(Ecore_Con_Url *url_con,
763 const char *content_type)
765 return _ecore_con_url_send(url_con, MODE_POST, data, length, content_type);
769 ecore_con_url_ftp_upload(Ecore_Con_Url *url_con,
770 const char *filename,
773 const char *upload_dir)
779 struct stat file_info;
782 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
784 ECORE_MAGIC_FAIL(url_con,
786 "ecore_con_url_ftp_upload");
798 if (stat(filename, &file_info))
801 snprintf(userpwd, sizeof(userpwd), "%s:%s", user, pass);
802 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERPWD, userpwd);
805 ERR("Could not set username and password for FTP upload: %s",
806 curl_easy_strerror(ret));
811 snprintf(tmp, PATH_MAX, "%s", filename);
814 snprintf(url, sizeof(url), "ftp://%s/%s/%s", url_con->url,
815 upload_dir, basename(tmp));
817 snprintf(url, sizeof(url), "ftp://%s/%s", url_con->url,
820 if (!ecore_con_url_url_set(url_con, url))
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);
829 fd = fopen(filename, "rb");
832 ERR("Could not open \"%s\" for FTP upload", filename);
835 curl_easy_setopt(url_con->curl_easy, CURLOPT_READDATA, fd);
837 return _ecore_con_url_perform(url_con);
852 ecore_con_url_cookies_init(Ecore_Con_Url *url_con)
858 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
860 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
861 "ecore_con_url_cookies_init");
865 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, "");
873 ecore_con_url_cookies_ignore_old_session_set(Ecore_Con_Url *url_con, Eina_Bool ignore)
879 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
881 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
882 "ecore_con_url_cookies_ignore_old_session_set");
886 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIESESSION, ignore);
895 ecore_con_url_cookies_clear(Ecore_Con_Url *url_con)
901 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
903 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
904 "ecore_con_url_cookies_clear");
908 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "ALL");
916 ecore_con_url_cookies_session_clear(Ecore_Con_Url *url_con)
922 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
924 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
925 "ecore_con_url_cookies_session_clear");
929 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "SESS");
937 ecore_con_url_cookies_file_add(Ecore_Con_Url *url_con, const char * const file_name)
943 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
945 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
946 "ecore_con_url_cookies_file_add");
950 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEFILE, file_name);
959 ecore_con_url_cookies_jar_file_set(Ecore_Con_Url *url_con, const char * const cookiejar_file)
967 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
969 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
970 "ecore_con_url_cookies_jar_file_set");
974 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIEJAR,
978 ERR("Setting the cookie-jar name failed: %s",
979 curl_easy_strerror(ret));
987 (void)cookiejar_file;
992 ecore_con_url_cookies_jar_write(Ecore_Con_Url *url_con)
998 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1000 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
1001 "ecore_con_url_cookies_jar_write");
1005 curl_easy_setopt(url_con->curl_easy, CURLOPT_COOKIELIST, "FLUSH");
1013 ecore_con_url_verbose_set(Ecore_Con_Url *url_con,
1017 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1019 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
1020 "ecore_con_url_verbose_set");
1024 if (url_con->active)
1030 curl_easy_setopt(url_con->curl_easy, CURLOPT_VERBOSE, (int)verbose);
1039 ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con,
1043 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1045 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
1046 "ecore_con_url_ftp_use_epsv_set");
1050 if (url_con->active)
1056 curl_easy_setopt(url_con->curl_easy, CURLOPT_FTP_USE_EPSV, (int)use_epsv);
1065 * Toggle libcurl's verify peer's certificate option.
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.
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.
1077 ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con,
1081 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1083 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL,
1084 "ecore_con_url_ssl_verify_peer_set");
1088 if (url_con->active)
1094 curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, (int)verify);
1103 * Set a custom CA to trust for SSL/TLS connections.
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.
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).
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
1117 * @return @c 0 on success. When cURL is used, non-zero return values
1118 * are equal to cURL error codes.
1121 ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
1126 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1128 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_ssl_ca_set");
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);
1138 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 1);
1140 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_CAINFO, ca_path);
1158 _ecore_con_url_suspend_fd_handler(void)
1161 Ecore_Con_Url *url_con;
1167 EINA_LIST_FOREACH(_url_con_list, l, url_con)
1169 if (url_con->active && url_con->fd_handler)
1171 ecore_main_fd_handler_del(url_con->fd_handler);
1172 url_con->fd_handler = NULL;
1181 _ecore_con_url_restart_fd_handler(void)
1184 Ecore_Con_Url *url_con;
1190 EINA_LIST_FOREACH(_url_con_list, l, url_con)
1192 if (!url_con->fd_handler && url_con->fd != -1)
1194 url_con->fd_handler =
1195 ecore_main_fd_handler_add(url_con->fd, url_con->flags,
1196 _ecore_con_url_fd_handler,
1206 _ecore_con_url_data_cb(void *buffer,
1211 Ecore_Con_Url *url_con;
1212 Ecore_Con_Event_Url_Data *e;
1213 size_t real_size = size * nitems;
1215 url_con = (Ecore_Con_Url *)userp;
1220 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1222 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_data_cb");
1226 url_con->received += real_size;
1228 if (url_con->write_fd < 0)
1231 malloc(sizeof(Ecore_Con_Event_Url_Data) + sizeof(unsigned char) *
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);
1245 size_t total_size = real_size;
1248 while (total_size > 0)
1250 count = write(url_con->write_fd,
1251 (char *)buffer + offset,
1255 if (errno != EAGAIN && errno != EINTR)
1260 total_size -= count;
1269 #define ECORE_CON_URL_TRANSMISSION(Transmit, Event, Url_con, Total, Now) \
1271 Ecore_Con_Event_Url_Progress *e; \
1272 if ((Total != 0) || (Now != 0)) \
1274 e = calloc(1, sizeof(Ecore_Con_Event_Url_Progress)); \
1277 e->url_con = url_con; \
1280 ecore_event_add(Event, e, _ecore_con_event_url_free, NULL); \
1286 _ecore_con_url_header_cb(void *ptr,
1291 size_t real_size = size * nitems;
1292 Ecore_Con_Url *url_con = stream;
1294 char *header = malloc(sizeof(char) * (real_size + 1));
1298 memcpy(header, ptr, real_size);
1299 header[real_size] = '\0';
1301 url_con->response_headers = eina_list_append(url_con->response_headers,
1308 _ecore_con_url_progress_cb(void *clientp,
1314 Ecore_Con_Event_Url_Progress *e;
1315 Ecore_Con_Url *url_con;
1319 e = malloc(sizeof(Ecore_Con_Event_Url_Progress));
1322 e->url_con = url_con;
1323 e->down.total = dltotal;
1324 e->down.now = dlnow;
1325 e->up.total = ultotal;
1327 ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e,
1328 _ecore_con_event_url_free, NULL);
1335 _ecore_con_url_read_cb(void *ptr,
1340 size_t retcode = fread(ptr, size, nitems, stream);
1342 if (ferror((FILE *)stream))
1345 return CURL_READFUNC_ABORT;
1347 else if (retcode == 0)
1349 fclose((FILE *)stream);
1354 INF("*** We read %Iu bytes from file", retcode);
1356 INF("*** We read %zu bytes from file", retcode);
1362 _ecore_con_url_perform(Ecore_Con_Url *url_con)
1364 fd_set read_set, write_set, exc_set;
1366 int flags, still_running;
1367 int completed_immediately = 0;
1370 _url_con_list = eina_list_append(_url_con_list, url_con);
1372 url_con->active = EINA_TRUE;
1373 curl_multi_add_handle(_curlm, url_con->curl_easy);
1374 curl_multi_perform(_curlm, &still_running);
1376 completed_immediately = _ecore_con_url_process_completed_jobs(url_con);
1378 if (!completed_immediately)
1380 if (url_con->fd_handler)
1381 ecore_main_fd_handler_del(url_con->fd_handler);
1383 url_con->fd_handler = NULL;
1385 /* url_con still active -- set up an fd_handler */
1387 FD_ZERO(&write_set);
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,
1393 if (ret != CURLM_OK)
1395 ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
1399 for (fd = 0; fd <= fd_max; fd++)
1401 if (!FD_ISSET(fd, &_current_fd_set))
1404 if (FD_ISSET(fd, &read_set))
1405 flags |= ECORE_FD_READ;
1407 if (FD_ISSET(fd, &write_set))
1408 flags |= ECORE_FD_WRITE;
1410 if (FD_ISSET(fd, &exc_set))
1411 flags |= ECORE_FD_ERROR;
1417 ret = curl_multi_timeout(_curlm, &ms);
1418 if (ret != CURLM_OK)
1419 ERR("curl_multi_timeout failed: %s",
1420 curl_multi_strerror(ret));
1425 FD_SET(fd, &_current_fd_set);
1427 url_con->flags = flags;
1428 url_con->fd_handler =
1429 ecore_main_fd_handler_add(fd, flags,
1430 _ecore_con_url_fd_handler,
1436 if (!url_con->fd_handler)
1438 /* Failed to set up an fd_handler */
1439 ecore_timer_freeze(_curl_timeout);
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));
1446 url_con->active = EINA_FALSE;
1451 ecore_timer_thaw(_curl_timeout);
1458 _ecore_con_url_idler_handler(void *data)
1460 int done, still_running;
1462 done = (curl_multi_perform(_curlm, &still_running) != CURLM_CALL_MULTI_PERFORM);
1464 _ecore_con_url_process_completed_jobs(NULL);
1468 _ecore_con_url_restart_fd_handler();
1469 _fd_idler_handler = NULL;
1472 ecore_timer_freeze(_curl_timeout);
1475 (void *)0xACE ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL;
1478 return ECORE_CALLBACK_RENEW;
1482 _ecore_con_url_fd_handler(void *data __UNUSED__,
1483 Ecore_Fd_Handler *fd_handler __UNUSED__)
1485 _ecore_con_url_suspend_fd_handler();
1487 if (!_fd_idler_handler)
1488 _fd_idler_handler = ecore_idler_add(
1489 _ecore_con_url_idler_handler, NULL);
1491 return ECORE_CALLBACK_RENEW;
1495 _ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match)
1498 Ecore_Con_Url *url_con;
1499 Ecore_Con_Event_Url_Complete *e;
1503 int job_matched = 0;
1505 /* Loop jobs and check if any are done */
1506 while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
1508 if (curlmsg->msg != CURLMSG_DONE)
1511 /* find the job which is done */
1512 EINA_LIST_FOREACH(_url_con_list, l, url_con)
1514 if (curlmsg->easy_handle == url_con->curl_easy)
1516 if (url_con_to_match &&
1517 (url_con == url_con_to_match))
1520 if(url_con->fd != -1)
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);
1528 url_con->fd_handler = NULL;
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));
1536 e->url_con = url_con;
1538 if (curlmsg->data.result == CURLE_OK)
1540 long status; /* curl API uses long, not int */
1543 curl_easy_getinfo(curlmsg->easy_handle,
1544 CURLINFO_RESPONSE_CODE,
1549 _url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e);
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));
1566 _ecore_con_event_url_free(void *data __UNUSED__,