aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_con/ecore_con_url.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore_con/ecore_con_url.c')
-rw-r--r--libraries/ecore/src/lib/ecore_con/ecore_con_url.c734
1 files changed, 387 insertions, 347 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
index cfcf095..709b554 100644
--- a/libraries/ecore/src/lib/ecore_con/ecore_con_url.c
+++ b/libraries/ecore/src/lib/ecore_con/ecore_con_url.c
@@ -35,8 +35,6 @@ int ECORE_CON_EVENT_URL_COMPLETE = 0;
35int ECORE_CON_EVENT_URL_PROGRESS = 0; 35int ECORE_CON_EVENT_URL_PROGRESS = 0;
36 36
37#ifdef HAVE_CURL 37#ifdef HAVE_CURL
38static Eina_Bool _ecore_con_url_fd_handler(void *data,
39 Ecore_Fd_Handler *fd_handler);
40static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con); 38static Eina_Bool _ecore_con_url_perform(Ecore_Con_Url *url_con);
41static size_t _ecore_con_url_header_cb(void *ptr, 39static size_t _ecore_con_url_header_cb(void *ptr,
42 size_t size, 40 size_t size,
@@ -57,50 +55,18 @@ static size_t _ecore_con_url_read_cb(void *ptr,
57 void *stream); 55 void *stream);
58static void _ecore_con_event_url_free(void *data __UNUSED__, 56static void _ecore_con_event_url_free(void *data __UNUSED__,
59 void *ev); 57 void *ev);
60static int _ecore_con_url_process_completed_jobs(
61 Ecore_Con_Url *url_con_to_match);
62static Eina_Bool _ecore_con_url_idler_handler(void *data); 58static Eina_Bool _ecore_con_url_idler_handler(void *data);
59static Eina_Bool _ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__);
60static Eina_Bool _ecore_con_url_timeout_cb(void *data);
63 61
64static Ecore_Idler *_fd_idler_handler = NULL;
65static Eina_List *_url_con_list = NULL; 62static Eina_List *_url_con_list = NULL;
63static Eina_List *_fd_hd_list = NULL;
66static CURLM *_curlm = NULL; 64static CURLM *_curlm = NULL;
67static fd_set _current_fd_set; 65static fd_set _current_fd_set;
68static int _init_count = 0; 66static int _init_count = 0;
69static Ecore_Timer *_curl_timeout = NULL; 67static Ecore_Timer *_curl_timeout = NULL;
70static Eina_Bool pipelining = EINA_FALSE; 68static Eina_Bool pipelining = EINA_FALSE;
71 69
72typedef struct _Ecore_Con_Url_Event Ecore_Con_Url_Event;
73struct _Ecore_Con_Url_Event
74{
75 int type;
76 void *ev;
77};
78
79static 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
91static 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 70#endif
105 71
106/** 72/**
@@ -113,51 +79,30 @@ EAPI int
113ecore_con_url_init(void) 79ecore_con_url_init(void)
114{ 80{
115#ifdef HAVE_CURL 81#ifdef HAVE_CURL
116 _init_count++; 82 if (++_init_count > 1) return _init_count;
117
118 if (_init_count > 1)
119 return _init_count;
120 83
121 if (!ECORE_CON_EVENT_URL_DATA) 84 if (!ECORE_CON_EVENT_URL_DATA) ECORE_CON_EVENT_URL_DATA = ecore_event_type_new();
122 { 85 if (!ECORE_CON_EVENT_URL_COMPLETE) ECORE_CON_EVENT_URL_COMPLETE = ecore_event_type_new();
123 ECORE_CON_EVENT_URL_DATA = ecore_event_type_new(); 86 if (!ECORE_CON_EVENT_URL_PROGRESS) ECORE_CON_EVENT_URL_PROGRESS = 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 87
128 if (!_curlm) 88 if (!_curlm)
129 { 89 {
130 long ms; 90 long ms;
131 91
132 FD_ZERO(&_current_fd_set); 92 // curl_global_init() is not thread safe!
133 if (curl_global_init(CURL_GLOBAL_ALL)) 93 if (curl_global_init(CURL_GLOBAL_ALL)) return --_init_count;
134 {
135 while (_url_con_list)
136 ecore_con_url_free(eina_list_data_get(_url_con_list));
137 return 0;
138 }
139 94
140 _curlm = curl_multi_init(); 95 _curlm = curl_multi_init();
141 if (!_curlm) 96 if (!_curlm) return --_init_count;
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 97
150 curl_multi_timeout(_curlm, &ms); 98 curl_multi_timeout(_curlm, &ms);
151 if (ms <= 0) 99 if (ms <= 0) ms = 100;
152 ms = 1000;
153 100
154 _curl_timeout = 101 _curl_timeout = ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler, (void *)0xACE);
155 ecore_timer_add((double)ms / 1000, _ecore_con_url_idler_handler,
156 (void *)0xACE);
157 ecore_timer_freeze(_curl_timeout); 102 ecore_timer_freeze(_curl_timeout);
158 } 103 }
159 104
160 return 1; 105 return _init_count;
161#else 106#else
162 return 0; 107 return 0;
163#endif 108#endif
@@ -167,34 +112,31 @@ EAPI int
167ecore_con_url_shutdown(void) 112ecore_con_url_shutdown(void)
168{ 113{
169#ifdef HAVE_CURL 114#ifdef HAVE_CURL
170 if (!_init_count) 115 if (_init_count == 0) return 0;
171 return 0;
172
173 _init_count--;
174 116
175 if (_init_count != 0) 117 if (--_init_count == 0)
176 return _init_count; 118 {
177 119 Ecore_Con_Url *con_url;
178 if (_fd_idler_handler) 120 Ecore_Fd_Handler *fd_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 121
188 while (_url_con_list) 122 if (_curl_timeout)
189 ecore_con_url_free(eina_list_data_get(_url_con_list)); 123 {
124 ecore_timer_del(_curl_timeout);
125 _curl_timeout = NULL;
126 }
190 127
191 if (_curlm) 128 FD_ZERO(&_current_fd_set);
192 { 129 EINA_LIST_FREE(_url_con_list, con_url) ecore_con_url_free(con_url);
193 curl_multi_cleanup(_curlm); 130 EINA_LIST_FREE(_fd_hd_list, fd_handler) ecore_main_fd_handler_del(fd_handler);
194 _curlm = NULL;
195 }
196 131
197 curl_global_cleanup(); 132 if (_curlm)
133 {
134 curl_multi_cleanup(_curlm);
135 _curlm = NULL;
136 }
137 curl_global_cleanup();
138 }
139 return _init_count;
198#endif 140#endif
199 return 1; 141 return 1;
200} 142}
@@ -237,7 +179,6 @@ ecore_con_url_new(const char *url)
237 if (!url_con) 179 if (!url_con)
238 return NULL; 180 return NULL;
239 181
240 url_con->fd = -1;
241 url_con->write_fd = -1; 182 url_con->write_fd = -1;
242 183
243 url_con->curl_easy = curl_easy_init(); 184 url_con->curl_easy = curl_easy_init();
@@ -255,6 +196,24 @@ ecore_con_url_new(const char *url)
255 return NULL; 196 return NULL;
256 } 197 }
257 198
199 url_con->proxy_type = -1;
200 if (_ecore_con_proxy_global)
201 {
202 if (_ecore_con_proxy_global->ip)
203 {
204 char host[128];
205 if (_ecore_con_proxy_global->port > 0 &&
206 _ecore_con_proxy_global->port <= 65535)
207 snprintf(host, sizeof(host), "socks4://%s:%d",
208 _ecore_con_proxy_global->ip,
209 _ecore_con_proxy_global->port);
210 else
211 snprintf(host, sizeof(host), "socks4://%s",
212 _ecore_con_proxy_global->ip);
213 ecore_con_url_proxy_set(url_con, host);
214 }
215 }
216
258 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate"); 217 ret = curl_easy_setopt(url_con->curl_easy, CURLOPT_ENCODING, "gzip,deflate");
259 if (ret != CURLE_OK) 218 if (ret != CURLE_OK)
260 { 219 {
@@ -344,43 +303,30 @@ ecore_con_url_free(Ecore_Con_Url *url_con)
344 } 303 }
345 304
346 ECORE_MAGIC_SET(url_con, ECORE_MAGIC_NONE); 305 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 306
357 if (url_con->curl_easy) 307 if (url_con->curl_easy)
358 { 308 {
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); 309 curl_easy_setopt(url_con->curl_easy, CURLOPT_PROGRESSFUNCTION, NULL);
362 curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE); 310 curl_easy_setopt(url_con->curl_easy, CURLOPT_NOPROGRESS, EINA_TRUE);
363 311
364 if (url_con->active) 312 if (eina_list_data_find(_url_con_list, url_con))
365 { 313 {
366 url_con->active = EINA_FALSE;
367
368 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); 314 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
369 if (ret != CURLM_OK) 315 if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
370 ERR("curl_multi_remove_handle failed: %s", 316 _url_con_list = eina_list_remove(_url_con_list, url_con);
371 curl_multi_strerror(ret));
372 } 317 }
373 318
374 curl_easy_cleanup(url_con->curl_easy); 319 curl_easy_cleanup(url_con->curl_easy);
375 } 320 }
321 if (url_con->timer) ecore_timer_del(url_con->timer);
376 322
377 _url_con_list = eina_list_remove(_url_con_list, url_con);
378 curl_slist_free_all(url_con->headers); 323 curl_slist_free_all(url_con->headers);
379 EINA_LIST_FREE(url_con->additional_headers, s) 324 EINA_LIST_FREE(url_con->additional_headers, s)
380 free(s); 325 free(s);
381 EINA_LIST_FREE(url_con->response_headers, s) 326 EINA_LIST_FREE(url_con->response_headers, s)
382 free(s); 327 free(s);
383 eina_stringshare_del(url_con->url); 328 eina_stringshare_del(url_con->url);
329 if (url_con->post_data) free(url_con->post_data);
384 free(url_con); 330 free(url_con);
385#else 331#else
386 return; 332 return;
@@ -415,8 +361,7 @@ ecore_con_url_url_set(Ecore_Con_Url *url_con,
415 return EINA_FALSE; 361 return EINA_FALSE;
416 } 362 }
417 363
418 if (url_con->active) 364 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
419 return EINA_FALSE;
420 365
421 eina_stringshare_replace(&url_con->url, url); 366 eina_stringshare_replace(&url_con->url, url);
422 367
@@ -660,7 +605,7 @@ _ecore_con_url_send(Ecore_Con_Url *url_con,
660#ifdef HAVE_CURL 605#ifdef HAVE_CURL
661 Eina_List *l; 606 Eina_List *l;
662 const char *s; 607 const char *s;
663 char tmp[256]; 608 char tmp[512];
664 609
665 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL)) 610 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
666 { 611 {
@@ -668,8 +613,7 @@ _ecore_con_url_send(Ecore_Con_Url *url_con,
668 return EINA_FALSE; 613 return EINA_FALSE;
669 } 614 }
670 615
671 if (url_con->active) 616 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
672 return EINA_FALSE;
673 617
674 if (!url_con->url) 618 if (!url_con->url)
675 return EINA_FALSE; 619 return EINA_FALSE;
@@ -684,16 +628,24 @@ _ecore_con_url_send(Ecore_Con_Url *url_con,
684 628
685 if ((mode == MODE_POST) || (mode == MODE_AUTO)) 629 if ((mode == MODE_POST) || (mode == MODE_AUTO))
686 { 630 {
687 if (data) 631 if (url_con->post_data) free(url_con->post_data);
632 url_con->post_data = NULL;
633 if ((data) && (length > 0))
688 { 634 {
689 if ((content_type) && (strlen(content_type) < 200)) 635 url_con->post_data = malloc(length);
636 if (url_con->post_data)
690 { 637 {
691 snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type); 638 memcpy(url_con->post_data, data, length);
692 url_con->headers = curl_slist_append(url_con->headers, tmp); 639 if ((content_type) && (strlen(content_type) < 450))
640 {
641 snprintf(tmp, sizeof(tmp), "Content-Type: %s", content_type);
642 url_con->headers = curl_slist_append(url_con->headers, tmp);
643 }
644 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, url_con->post_data);
645 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length);
693 } 646 }
694 647 else
695 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDS, data); 648 return EINA_FALSE;
696 curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, length);
697 } 649 }
698 else curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, 0); 650 else curl_easy_setopt(url_con->curl_easy, CURLOPT_POSTFIELDSIZE, 0);
699 if (mode == MODE_POST) 651 if (mode == MODE_POST)
@@ -787,8 +739,7 @@ ecore_con_url_ftp_upload(Ecore_Con_Url *url_con,
787 return EINA_FALSE; 739 return EINA_FALSE;
788 } 740 }
789 741
790 if (url_con->active) 742 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
791 return EINA_FALSE;
792 743
793 if (!url_con->url) 744 if (!url_con->url)
794 return EINA_FALSE; 745 return EINA_FALSE;
@@ -1021,8 +972,7 @@ ecore_con_url_verbose_set(Ecore_Con_Url *url_con,
1021 return; 972 return;
1022 } 973 }
1023 974
1024 if (url_con->active) 975 if (eina_list_data_find(_url_con_list, url_con)) return;
1025 return;
1026 976
1027 if (!url_con->url) 977 if (!url_con->url)
1028 return; 978 return;
@@ -1047,8 +997,7 @@ ecore_con_url_ftp_use_epsv_set(Ecore_Con_Url *url_con,
1047 return; 997 return;
1048 } 998 }
1049 999
1050 if (url_con->active) 1000 if (eina_list_data_find(_url_con_list, url_con)) return;
1051 return;
1052 1001
1053 if (!url_con->url) 1002 if (!url_con->url)
1054 return; 1003 return;
@@ -1085,8 +1034,7 @@ ecore_con_url_ssl_verify_peer_set(Ecore_Con_Url *url_con,
1085 return; 1034 return;
1086 } 1035 }
1087 1036
1088 if (url_con->active) 1037 if (eina_list_data_find(_url_con_list, url_con)) return;
1089 return;
1090 1038
1091 if (!url_con->url) 1039 if (!url_con->url)
1092 return; 1040 return;
@@ -1129,7 +1077,7 @@ ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
1129 return -1; 1077 return -1;
1130 } 1078 }
1131 1079
1132 if (url_con->active) return -1; 1080 if (eina_list_data_find(_url_con_list, url_con)) return -1;
1133 if (!url_con->url) return -1; 1081 if (!url_con->url) return -1;
1134 if (ca_path == NULL) 1082 if (ca_path == NULL)
1135 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0); 1083 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_SSL_VERIFYPEER, 0);
@@ -1148,58 +1096,180 @@ ecore_con_url_ssl_ca_set(Ecore_Con_Url *url_con, const char *ca_path)
1148 return res; 1096 return res;
1149} 1097}
1150 1098
1151 1099EAPI Eina_Bool
1152/** 1100ecore_con_url_proxy_set(Ecore_Con_Url *url_con, const char *proxy)
1153 * @}
1154 */
1155
1156#ifdef HAVE_CURL
1157static int
1158_ecore_con_url_suspend_fd_handler(void)
1159{ 1101{
1160 Eina_List *l; 1102#ifdef HAVE_CURL
1161 Ecore_Con_Url *url_con; 1103 int res = -1;
1162 int deleted = 0; 1104 curl_version_info_data *vers = NULL;
1163 1105
1164 if (!_url_con_list) 1106 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1165 return 0; 1107 {
1108 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_set");
1109 return EINA_FALSE;
1110 }
1166 1111
1167 EINA_LIST_FOREACH(_url_con_list, l, url_con) 1112 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
1113 if (!url_con->url) return EINA_FALSE;
1114
1115 if (!proxy) res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, "");
1116 else
1168 { 1117 {
1169 if (url_con->active && url_con->fd_handler) 1118 // before curl version 7.21.7, socks protocol:// prefix is not supported
1119 // (e.g. socks4://, socks4a://, socks5:// or socks5h://, etc.)
1120 vers = curl_version_info(CURLVERSION_NOW);
1121 if (vers->version_num < 0x71507)
1170 { 1122 {
1171 ecore_main_fd_handler_del(url_con->fd_handler); 1123 url_con->proxy_type = CURLPROXY_HTTP;
1172 url_con->fd_handler = NULL; 1124 if (strstr(proxy, "socks4")) url_con->proxy_type = CURLPROXY_SOCKS4;
1173 deleted++; 1125 else if (strstr(proxy, "socks4a")) url_con->proxy_type = CURLPROXY_SOCKS4A;
1126 else if (strstr(proxy, "socks5")) url_con->proxy_type = CURLPROXY_SOCKS5;
1127 else if (strstr(proxy, "socks5h")) url_con->proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
1128 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXYTYPE, url_con->proxy_type);
1129 if (res != CURLE_OK)
1130 {
1131 ERR("curl proxy type setting failed: %s", curl_easy_strerror(res));
1132 url_con->proxy_type = -1;
1133 return EINA_FALSE;
1134 }
1174 } 1135 }
1136 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PROXY, proxy);
1137 }
1138 if (res != CURLE_OK)
1139 {
1140 ERR("curl proxy setting failed: %s", curl_easy_strerror(res));
1141 url_con->proxy_type = -1;
1142 return EINA_FALSE;
1143 }
1144 return EINA_TRUE;
1145#else
1146 return EINA_FALSE;
1147 (void)url_con;
1148 (void)proxy;
1149#endif
1150}
1151
1152EAPI void
1153ecore_con_url_timeout_set(Ecore_Con_Url *url_con, double timeout)
1154{
1155#ifdef HAVE_CURL
1156 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1157 {
1158 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_timeout_set");
1159 return;
1175 } 1160 }
1176 1161
1177 return deleted; 1162 if (eina_list_data_find(_url_con_list, url_con)) return;
1163 if (!url_con->url || timeout < 0) return;
1164 if (url_con->timer) ecore_timer_del(url_con->timer);
1165 url_con->timer = ecore_timer_add(timeout, _ecore_con_url_timeout_cb, url_con);
1166#else
1167 return;
1168 (void)url_con;
1169 (void)timeout;
1170#endif
1178} 1171}
1179 1172
1180static int 1173EAPI Eina_Bool
1181_ecore_con_url_restart_fd_handler(void) 1174ecore_con_url_proxy_username_set(Ecore_Con_Url *url_con, const char *username)
1182{ 1175{
1183 Eina_List *l; 1176#ifdef HAVE_CURL
1184 Ecore_Con_Url *url_con; 1177 int res = -1;
1185 int activated = 0; 1178 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1179 {
1180 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_username_set");
1181 return EINA_FALSE;
1182 }
1186 1183
1187 if (!_url_con_list) 1184 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
1188 return 0; 1185 if (!url_con->url) return EINA_FALSE;
1186 if (!username) return EINA_FALSE;
1187 if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
1188 {
1189 ERR("Proxy type should be socks5 and above");
1190 return EINA_FALSE;
1191 }
1189 1192
1190 EINA_LIST_FOREACH(_url_con_list, l, url_con) 1193 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_USERNAME, username);
1194 if (res != CURLE_OK)
1191 { 1195 {
1192 if (!url_con->fd_handler && url_con->fd != -1) 1196 ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
1193 { 1197 return EINA_FALSE;
1194 url_con->fd_handler = 1198 }
1195 ecore_main_fd_handler_add(url_con->fd, url_con->flags, 1199 return EINA_TRUE;
1196 _ecore_con_url_fd_handler, 1200#else
1197 NULL, NULL, NULL); 1201 return EINA_FALSE;
1198 activated++; 1202 (void)url_con;
1199 } 1203 (void)username;
1204#endif
1205}
1206
1207EAPI Eina_Bool
1208ecore_con_url_proxy_password_set(Ecore_Con_Url *url_con, const char *password)
1209{
1210#ifdef HAVE_CURL
1211 int res = -1;
1212 if (!ECORE_MAGIC_CHECK(url_con, ECORE_MAGIC_CON_URL))
1213 {
1214 ECORE_MAGIC_FAIL(url_con, ECORE_MAGIC_CON_URL, "ecore_con_url_proxy_password_set");
1215 return EINA_FALSE;
1216 }
1217 if (eina_list_data_find(_url_con_list, url_con)) return EINA_FALSE;
1218 if (!url_con->url) return EINA_FALSE;
1219 if (!password) return EINA_FALSE;
1220 if (url_con->proxy_type == CURLPROXY_SOCKS4 || url_con->proxy_type == CURLPROXY_SOCKS4A)
1221 {
1222 ERR("Proxy type should be socks5 and above");
1223 return EINA_FALSE;
1224 }
1225
1226 res = curl_easy_setopt(url_con->curl_easy, CURLOPT_PASSWORD, password);
1227 if (res != CURLE_OK)
1228 {
1229 ERR("curl_easy_setopt() failed: %s", curl_easy_strerror(res));
1230 return EINA_FALSE;
1200 } 1231 }
1232 return EINA_TRUE;
1233#else
1234 return EINA_FALSE;
1235 (void)url_con;
1236 (void)password;
1237#endif
1238}
1239
1240/**
1241 * @}
1242 */
1201 1243
1202 return activated; 1244#ifdef HAVE_CURL
1245static Eina_Bool
1246_ecore_con_url_timeout_cb(void *data)
1247{
1248 Ecore_Con_Url *url_con = data;
1249 CURLMcode ret;
1250 Ecore_Con_Event_Url_Complete *e;
1251
1252 if (!url_con) return ECORE_CALLBACK_CANCEL;
1253 if (!url_con->curl_easy) return ECORE_CALLBACK_CANCEL;
1254 if (!eina_list_data_find(_url_con_list, url_con)) return ECORE_CALLBACK_CANCEL;
1255
1256 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
1257 if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
1258 _url_con_list = eina_list_remove(_url_con_list, url_con);
1259
1260 curl_slist_free_all(url_con->headers);
1261 url_con->headers = NULL;
1262
1263 url_con->timer = NULL;
1264
1265 e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
1266 if (e)
1267 {
1268 e->url_con = url_con;
1269 e->status = 0;
1270 ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, _ecore_con_event_url_free, NULL);
1271 }
1272 return ECORE_CALLBACK_CANCEL;
1203} 1273}
1204 1274
1205static size_t 1275static size_t
@@ -1235,8 +1305,7 @@ _ecore_con_url_data_cb(void *buffer,
1235 e->url_con = url_con; 1305 e->url_con = url_con;
1236 e->size = real_size; 1306 e->size = real_size;
1237 memcpy(e->data, buffer, real_size); 1307 memcpy(e->data, buffer, real_size);
1238 ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, 1308 ecore_event_add(ECORE_CON_EVENT_URL_DATA, e, _ecore_con_event_url_free, NULL);
1239 _ecore_con_event_url_free, NULL);
1240 } 1309 }
1241 } 1310 }
1242 else 1311 else
@@ -1266,22 +1335,6 @@ _ecore_con_url_data_cb(void *buffer,
1266 return real_size; 1335 return real_size;
1267} 1336}
1268 1337
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
1285static size_t 1338static size_t
1286_ecore_con_url_header_cb(void *ptr, 1339_ecore_con_url_header_cb(void *ptr,
1287 size_t size, 1340 size_t size,
@@ -1324,8 +1377,7 @@ _ecore_con_url_progress_cb(void *clientp,
1324 e->down.now = dlnow; 1377 e->down.now = dlnow;
1325 e->up.total = ultotal; 1378 e->up.total = ultotal;
1326 e->up.now = ulnow; 1379 e->up.now = ulnow;
1327 ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, 1380 ecore_event_add(ECORE_CON_EVENT_URL_PROGRESS, e, _ecore_con_event_url_free, NULL);
1328 _ecore_con_event_url_free, NULL);
1329 } 1381 }
1330 1382
1331 return 0; 1383 return 0;
@@ -1358,208 +1410,196 @@ _ecore_con_url_read_cb(void *ptr,
1358 return retcode; 1410 return retcode;
1359} 1411}
1360 1412
1361static Eina_Bool 1413static void
1362_ecore_con_url_perform(Ecore_Con_Url *url_con) 1414_ecore_con_url_info_read(void)
1363{ 1415{
1364 fd_set read_set, write_set, exc_set; 1416 CURLMsg *curlmsg;
1365 int fd_max, fd; 1417 int n_remaining;
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 1418
1378 if (!completed_immediately) 1419 while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining)))
1379 { 1420 {
1380 if (url_con->fd_handler) 1421 if (curlmsg->msg == CURLMSG_DONE)
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 { 1422 {
1395 ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret)); 1423 Eina_List *l, *ll;
1396 return EINA_FALSE; 1424 Ecore_Con_Url *url_con;
1397 }
1398 1425
1399 for (fd = 0; fd <= fd_max; fd++) 1426 EINA_LIST_FOREACH_SAFE(_url_con_list, l, ll, url_con)
1400 {
1401 if (!FD_ISSET(fd, &_current_fd_set))
1402 { 1427 {
1403 flags = 0; 1428 if (curlmsg->easy_handle == url_con->curl_easy)
1404 if (FD_ISSET(fd, &read_set)) 1429 {
1405 flags |= ECORE_FD_READ; 1430 CURLMcode ret;
1406 1431 Ecore_Con_Event_Url_Complete *e;
1407 if (FD_ISSET(fd, &write_set))
1408 flags |= ECORE_FD_WRITE;
1409 1432
1410 if (FD_ISSET(fd, &exc_set)) 1433 e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
1411 flags |= ECORE_FD_ERROR; 1434 if (e)
1435 {
1436 e->url_con = url_con;
1437 e->status = 0;
1438 if (curlmsg->data.result == CURLE_OK)
1439 {
1440 long status; /* curl API uses long, not int */
1441 status = 0;
1442 curl_easy_getinfo(curlmsg->easy_handle, CURLINFO_RESPONSE_CODE, &status);
1443 e->status = status;
1444 }
1445 ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, _ecore_con_event_url_free, NULL);
1446 }
1412 1447
1413 if (flags) 1448 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
1414 { 1449 if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
1415 long ms = 0; 1450 _url_con_list = eina_list_remove(_url_con_list, url_con);
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; 1451 break;
1433 } 1452 }
1434 } 1453 }
1435 } 1454 }
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 } 1455 }
1453
1454 return EINA_TRUE;
1455} 1456}
1456 1457
1457static Eina_Bool 1458static void
1458_ecore_con_url_idler_handler(void *data) 1459_ecore_con_url_curl_clear(void)
1459{ 1460{
1460 int done, still_running; 1461 Ecore_Con_Url *url_con;
1461
1462 done = (curl_multi_perform(_curlm, &still_running) != CURLM_CALL_MULTI_PERFORM);
1463
1464 _ecore_con_url_process_completed_jobs(NULL);
1465 1462
1466 if (done) 1463 FD_ZERO(&_current_fd_set);
1464 if (_fd_hd_list)
1467 { 1465 {
1468 _ecore_con_url_restart_fd_handler(); 1466 Ecore_Fd_Handler *fd_handler;
1469 _fd_idler_handler = NULL; 1467 EINA_LIST_FREE(_fd_hd_list, fd_handler)
1468 {
1469 int fd = ecore_main_fd_handler_fd_get(fd_handler);
1470 FD_CLR(fd, &_current_fd_set);
1471 // FIXME: ecore_main_fd_handler_del() sometimes give errors
1472 // because curl do not make fd itself controlled by users, but it can be ignored.
1473 ecore_main_fd_handler_del(fd_handler);
1474 }
1475 }
1470 1476
1471 if (!_url_con_list) 1477 EINA_LIST_FREE(_url_con_list, url_con)
1472 ecore_timer_freeze(_curl_timeout); 1478 {
1479 CURLMcode ret;
1480 Ecore_Con_Event_Url_Complete *e;
1473 1481
1474 return data == 1482 e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete));
1475 (void *)0xACE ? ECORE_CALLBACK_RENEW : ECORE_CALLBACK_CANCEL; 1483 if (e)
1484 {
1485 e->url_con = url_con;
1486 e->status = 0;
1487 ecore_event_add(ECORE_CON_EVENT_URL_COMPLETE, e, _ecore_con_event_url_free, NULL);
1488 }
1489 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy);
1490 if (ret != CURLM_OK) ERR("curl_multi_remove_handle failed: %s", curl_multi_strerror(ret));
1476 } 1491 }
1477
1478 return ECORE_CALLBACK_RENEW;
1479} 1492}
1480 1493
1481static Eina_Bool 1494static Eina_Bool
1482_ecore_con_url_fd_handler(void *data __UNUSED__, 1495_ecore_con_url_fd_handler(void *data __UNUSED__, Ecore_Fd_Handler *fd_handler __UNUSED__)
1483 Ecore_Fd_Handler *fd_handler __UNUSED__)
1484{ 1496{
1485 _ecore_con_url_suspend_fd_handler(); 1497 if (_fd_hd_list)
1486 1498 {
1487 if (!_fd_idler_handler) 1499 Ecore_Fd_Handler *fd_handler;
1488 _fd_idler_handler = ecore_idler_add( 1500 EINA_LIST_FREE(_fd_hd_list, fd_handler)
1489 _ecore_con_url_idler_handler, NULL); 1501 {
1490 1502 int fd = ecore_main_fd_handler_fd_get(fd_handler);
1503 FD_CLR(fd, &_current_fd_set);
1504 // FIXME: ecore_main_fd_handler_del() sometimes give errors
1505 // because curl do not make fd itself controlled by users, but it can be ignored.
1506 ecore_main_fd_handler_del(fd_handler);
1507 }
1508 }
1509 ecore_timer_thaw(_curl_timeout);
1491 return ECORE_CALLBACK_RENEW; 1510 return ECORE_CALLBACK_RENEW;
1492} 1511}
1493 1512
1494static int 1513static void
1495_ecore_con_url_process_completed_jobs(Ecore_Con_Url *url_con_to_match) 1514_ecore_con_url_fdset(void)
1496{ 1515{
1497 Eina_List *l;
1498 Ecore_Con_Url *url_con;
1499 Ecore_Con_Event_Url_Complete *e;
1500 CURLMsg *curlmsg;
1501 CURLMcode ret; 1516 CURLMcode ret;
1502 int n_remaining; 1517 fd_set read_set, write_set, exc_set;
1503 int job_matched = 0; 1518 int fd, fd_max;
1519 Ecore_Fd_Handler *fd_handler;
1504 1520
1505 /* Loop jobs and check if any are done */ 1521 FD_ZERO(&read_set);
1506 while ((curlmsg = curl_multi_info_read(_curlm, &n_remaining))) 1522 FD_ZERO(&write_set);
1523 FD_ZERO(&exc_set);
1524
1525 ret = curl_multi_fdset(_curlm, &read_set, &write_set, &exc_set, &fd_max);
1526 if (ret != CURLM_OK)
1507 { 1527 {
1508 if (curlmsg->msg != CURLMSG_DONE) 1528 ERR("curl_multi_fdset failed: %s", curl_multi_strerror(ret));
1509 continue; 1529 return;
1530 }
1510 1531
1511 /* find the job which is done */ 1532 for (fd = 0; fd <= fd_max; fd++)
1512 EINA_LIST_FOREACH(_url_con_list, l, url_con) 1533 {
1534 int flags = 0;
1535 if (FD_ISSET(fd, &read_set)) flags |= ECORE_FD_READ;
1536 if (FD_ISSET(fd, &write_set)) flags |= ECORE_FD_WRITE;
1537 if (FD_ISSET(fd, &exc_set)) flags |= ECORE_FD_ERROR;
1538 if (flags)
1513 { 1539 {
1514 if (curlmsg->easy_handle == url_con->curl_easy) 1540 if (!FD_ISSET(fd, &_current_fd_set))
1515 { 1541 {
1516 if (url_con_to_match && 1542 FD_SET(fd, &_current_fd_set);
1517 (url_con == url_con_to_match)) 1543 fd_handler = ecore_main_fd_handler_add(fd, flags, _ecore_con_url_fd_handler, NULL, NULL, NULL);
1518 job_matched = 1; 1544 if (fd_handler) _fd_hd_list = eina_list_append(_fd_hd_list, fd_handler);
1519 1545 ecore_timer_freeze(_curl_timeout);
1520 if(url_con->fd != -1) 1546 }
1521 { 1547 }
1522 FD_CLR(url_con->fd, &_current_fd_set); 1548 }
1523 if (url_con->fd_handler) 1549}
1524 ecore_main_fd_handler_del(
1525 url_con->fd_handler);
1526 1550
1527 url_con->fd = -1; 1551static Eina_Bool
1528 url_con->fd_handler = NULL; 1552_ecore_con_url_idler_handler(void *data __UNUSED__)
1529 } 1553{
1554 int still_running;
1555 CURLMcode ret;
1530 1556
1531 _url_con_list = eina_list_remove(_url_con_list, url_con); 1557 ret = curl_multi_perform(_curlm, &still_running);
1532 url_con->active = EINA_FALSE; 1558 if (ret == CURLM_CALL_MULTI_PERFORM)
1533 e = calloc(1, sizeof(Ecore_Con_Event_Url_Complete)); 1559 {
1534 if (e) 1560 DBG("Call multiperform again");
1535 { 1561 return ECORE_CALLBACK_RENEW;
1536 e->url_con = url_con; 1562 }
1537 e->status = 0; 1563 else if (ret != CURLM_OK)
1538 if (curlmsg->data.result == CURLE_OK) 1564 {
1539 { 1565 ERR("curl_multi_perform() failed: %s", curl_multi_strerror(ret));
1540 long status; /* curl API uses long, not int */ 1566 _ecore_con_url_curl_clear();
1567 ecore_timer_freeze(_curl_timeout);
1568 return ECORE_CALLBACK_RENEW;
1569 }
1541 1570
1542 status = 0; 1571 _ecore_con_url_info_read();
1543 curl_easy_getinfo(curlmsg->easy_handle, 1572 if (still_running)
1544 CURLINFO_RESPONSE_CODE, 1573 {
1545 &status); 1574 DBG("multiperform is still_running");
1546 e->status = status; 1575 _ecore_con_url_fdset();
1547 } 1576 }
1577 else
1578 {
1579 DBG("multiperform ended");
1580 _ecore_con_url_curl_clear();
1581 ecore_timer_freeze(_curl_timeout);
1582 }
1548 1583
1549 _url_complete_push_event(ECORE_CON_EVENT_URL_COMPLETE, e); 1584 return ECORE_CALLBACK_RENEW;
1550 } 1585}
1551 1586
1552 ret = curl_multi_remove_handle(_curlm, url_con->curl_easy); 1587static Eina_Bool
1553 if (ret != CURLM_OK) 1588_ecore_con_url_perform(Ecore_Con_Url *url_con)
1554 ERR("curl_multi_remove_handle failed: %s", 1589{
1555 curl_multi_strerror(ret)); 1590 CURLMcode ret;
1556 1591
1557 break; 1592 ret = curl_multi_add_handle(_curlm, url_con->curl_easy);
1558 } 1593 if (ret != CURLM_OK)
1559 } 1594 {
1595 ERR("curl_multi_add_handle() failed: %s", curl_multi_strerror(ret));
1596 return EINA_FALSE;
1560 } 1597 }
1561 1598
1562 return job_matched; 1599 _url_con_list = eina_list_append(_url_con_list, url_con);
1600 ecore_timer_thaw(_curl_timeout);
1601
1602 return EINA_TRUE;
1563} 1603}
1564 1604
1565static void 1605static void