summaryrefslogtreecommitdiff
path: root/src/lib/ecore_file
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>2016-11-21 19:44:57 -0200
committerGustavo Sverzut Barbieri <barbieri@profusion.mobi>2016-11-21 19:47:35 -0200
commit02d352e1f29c32cb072c54308a43cde104f29bb8 (patch)
treea6bc1d1b350dae7ba464b1e4be724473ee994d49 /src/lib/ecore_file
parent2e3aa2cf6c39cbe599fcf1adf8984e205960e125 (diff)
ecore_file_download: use new efl_net_dialer_http.
Greatly reduce code complexity while providing better support, at least according to @netstar efl_net_dialer_http works better than traditional ecore_con_url on BSD.
Diffstat (limited to 'src/lib/ecore_file')
-rw-r--r--src/lib/ecore_file/ecore_file_download.c400
1 files changed, 203 insertions, 197 deletions
diff --git a/src/lib/ecore_file/ecore_file_download.c b/src/lib/ecore_file/ecore_file_download.c
index e9c047f7c1..3ed475a9fb 100644
--- a/src/lib/ecore_file/ecore_file_download.c
+++ b/src/lib/ecore_file/ecore_file_download.c
@@ -5,6 +5,7 @@
5#include <stdlib.h> 5#include <stdlib.h>
6#include <stdio.h> 6#include <stdio.h>
7#include <string.h> 7#include <string.h>
8#include <fcntl.h>
8 9
9# include "Ecore_Con.h" 10# include "Ecore_Con.h"
10 11
@@ -17,28 +18,16 @@ struct _Ecore_File_Download_Job
17{ 18{
18 ECORE_MAGIC; 19 ECORE_MAGIC;
19 20
20 Ecore_Con_Url *url_con; 21 Eo *input;
21 FILE *file; 22 Eo *output;
22 23 Eo *copier;
23 char *dst;
24 24
25 Ecore_File_Download_Completion_Cb completion_cb; 25 Ecore_File_Download_Completion_Cb completion_cb;
26 Ecore_File_Download_Progress_Cb progress_cb; 26 Ecore_File_Download_Progress_Cb progress_cb;
27 const void *data;
27}; 28};
28 29
29Ecore_File_Download_Job *_ecore_file_download_curl(const char *url, const char *dst,
30 Ecore_File_Download_Completion_Cb completion_cb,
31 Ecore_File_Download_Progress_Cb progress_cb,
32 void *data,
33 Eina_Hash *headers);
34
35static Eina_Bool _ecore_file_download_url_complete_cb(void *data, int type, void *event);
36static Eina_Bool _ecore_file_download_url_progress_cb(void *data, int type, void *event);
37
38static Ecore_Event_Handler *_url_complete_handler = NULL;
39static Ecore_Event_Handler *_url_progress_download = NULL;
40static Eina_List *_job_list; 30static Eina_List *_job_list;
41
42static int download_init = 0; 31static int download_init = 0;
43 32
44int 33int
@@ -46,15 +35,18 @@ ecore_file_download_init(void)
46{ 35{
47 download_init++; 36 download_init++;
48 if (download_init > 1) return 1; 37 if (download_init > 1) return 1;
49 if (!ecore_con_init()) return 0; 38 if (!ecore_con_init())
39 {
40 download_init--;
41 return 0;
42 }
50 if (!ecore_con_url_init()) 43 if (!ecore_con_url_init())
51 { 44 {
52 ecore_con_shutdown(); 45 ecore_con_shutdown();
46 download_init--;
53 return 0; 47 return 0;
54 } 48 }
55 _url_complete_handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _ecore_file_download_url_complete_cb, NULL); 49 return download_init;
56 _url_progress_download = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _ecore_file_download_url_progress_cb, NULL);
57 return 1;
58} 50}
59 51
60void 52void
@@ -62,232 +54,239 @@ ecore_file_download_shutdown(void)
62{ 54{
63 download_init--; 55 download_init--;
64 if (download_init > 0) return; 56 if (download_init > 0) return;
65 if (_url_complete_handler)
66 ecore_event_handler_del(_url_complete_handler);
67 if (_url_progress_download)
68 ecore_event_handler_del(_url_progress_download);
69 _url_complete_handler = NULL;
70 _url_progress_download = NULL;
71 ecore_file_download_abort_all(); 57 ecore_file_download_abort_all();
72 ecore_con_url_shutdown(); 58 ecore_con_url_shutdown();
73 ecore_con_shutdown(); 59 ecore_con_shutdown();
74} 60}
75 61
76static Eina_Bool 62static void
77_ecore_file_download_headers_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata) 63_ecore_file_download_copier_done(void *data, const Efl_Event *event EINA_UNUSED)
78{ 64{
79 Ecore_File_Download_Job *job = fdata; 65 Ecore_File_Download_Job *job = data;
80 ecore_con_url_additional_header_add(job->url_con, key, data); 66 Efl_Net_Http_Status status = efl_net_dialer_http_response_status_get(job->input);
67 const char *file;
81 68
82 return EINA_TRUE; 69 efl_file_get(job->output, &file, NULL);
83}
84 70
85static Eina_Bool 71 DBG("Finished downloading %s (status=%d) -> %s",
86_ecore_file_download(const char *url, 72 efl_net_dialer_address_dial_get(job->input),
87 const char *dst, 73 status,
88 Ecore_File_Download_Completion_Cb completion_cb, 74 file);
89 Ecore_File_Download_Progress_Cb progress_cb, 75
90 void *data, 76 if (job->completion_cb)
91 Ecore_File_Download_Job **job_ret,
92 Eina_Hash *headers)
93{
94 if (!url)
95 { 77 {
96 CRI("Download URL is null"); 78 Ecore_File_Download_Completion_Cb cb = job->completion_cb;
97 return EINA_FALSE; 79 job->completion_cb = NULL;
80 cb((void *)job->data, file, status);
98 } 81 }
99 82
100 char *dir = ecore_file_dir_get(dst); 83 efl_del(job->copier);
84}
101 85
102 if (!ecore_file_is_dir(dir)) 86static void
103 { 87_ecore_file_download_copier_error(void *data, const Efl_Event *event)
104 ERR("%s is not a directory", dir); 88{
105 free(dir); 89 Ecore_File_Download_Job *job = data;
106 return EINA_FALSE; 90 Efl_Net_Http_Status status = efl_net_dialer_http_response_status_get(job->input);
107 } 91 Eina_Error *perr = event->info;
108 free(dir); 92 const char *file;
109 if (ecore_file_exists(dst))
110 {
111 WRN("%s already exists", dst);
112 return EINA_FALSE;
113 }
114 93
115 if (!strncmp(url, "file://", 7)) 94 efl_file_get(job->output, &file, NULL);
116 { 95
117 /* FIXME: Maybe fork? Might take a while to copy. 96 WRN("Failed downloading %s (status=%d) -> %s: %s",
118 * Check filesize? */ 97 efl_net_dialer_address_dial_get(job->input),
119 /* Just copy it */ 98 efl_net_dialer_http_response_status_get(job->input),
120 99 file,
121 url += 7; 100 eina_error_msg_get(*perr));
122 /* skip hostname */ 101
123 if ((url = strchr(url, '/'))) 102 if (job->completion_cb)
124 return ecore_file_cp(url, dst);
125 else
126 return EINA_FALSE;
127 }
128 else if ((!strncmp(url, "http://", 7)) || (!strncmp(url, "https://", 8)) ||
129 (!strncmp(url, "ftp://", 6)))
130 { 103 {
131 /* download */ 104 Ecore_File_Download_Completion_Cb cb = job->completion_cb;
132 Ecore_File_Download_Job *job; 105 job->completion_cb = NULL;
133 106
134 job = _ecore_file_download_curl(url, dst, completion_cb, progress_cb, data, headers); 107 if ((status < 500) || ((int)status > 599))
135 if(job_ret) *job_ret = job;
136 if(job)
137 return EINA_TRUE;
138 else
139 { 108 {
140 ERR("no job returned\n"); 109 /* not an HTTP error, likely copier or output, use 500 */
141 return EINA_FALSE; 110 status = 500;
142 } 111 }
112
113 cb((void *)job->data, file, status);
143 } 114 }
144 else
145 {
146 return EINA_FALSE;
147 }
148}
149 115
150EAPI Eina_Bool 116 efl_del(job->copier);
151ecore_file_download(const char *url,
152 const char *dst,
153 Ecore_File_Download_Completion_Cb completion_cb,
154 Ecore_File_Download_Progress_Cb progress_cb,
155 void *data,
156 Ecore_File_Download_Job **job_ret)
157{
158 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, NULL);
159} 117}
160 118
161EAPI Eina_Bool 119static void
162ecore_file_download_full(const char *url, 120_ecore_file_download_copier_progress(void *data, const Efl_Event *event EINA_UNUSED)
163 const char *dst,
164 Ecore_File_Download_Completion_Cb completion_cb,
165 Ecore_File_Download_Progress_Cb progress_cb,
166 void *data,
167 Ecore_File_Download_Job **job_ret,
168 Eina_Hash *headers)
169{ 121{
170 return _ecore_file_download(url, dst, completion_cb, progress_cb, data, job_ret, headers); 122 Ecore_File_Download_Job *job = data;
171} 123 Ecore_File_Progress_Return ret;
124 uint64_t dn, dt, un, ut;
125 const char *file;
172 126
173EAPI Eina_Bool 127 if (!job->progress_cb) return;
174ecore_file_download_protocol_available(const char *protocol)
175{
176 if (!strncmp(protocol, "file://", 7)) return EINA_TRUE;
177 else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE;
178 else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE;
179 128
180 return EINA_FALSE; 129 efl_file_get(job->output, &file, NULL);
181} 130 efl_net_dialer_http_progress_download_get(job->input, &dn, &dt);
131 efl_net_dialer_http_progress_upload_get(job->input, &un, &ut);
132 ret = job->progress_cb((void *)job->data, file, dt, dn, ut, un);
182 133
183static int 134 if (ret == ECORE_FILE_PROGRESS_CONTINUE) return;
184_ecore_file_download_url_compare_job(const void *data1, const void *data2)
185{
186 const Ecore_File_Download_Job *job = data1;
187 const Ecore_Con_Url *url = data2;
188 135
189 if (job->url_con == url) return 0; 136 ecore_file_download_abort(job);
190 return -1;
191} 137}
192 138
193static Eina_Bool 139static void
194_ecore_file_download_url_complete_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) 140_ecore_file_download_copier_del(void *data, const Efl_Event *event EINA_UNUSED)
195{ 141{
196 Ecore_Con_Event_Url_Complete *ev = event; 142 Ecore_File_Download_Job *job = data;
197 Ecore_File_Download_Job *job;
198 143
199 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con); 144 ECORE_MAGIC_SET(job, ECORE_MAGIC_NONE);
200 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
201 145
202 fclose(job->file); 146 efl_del(job->input);
203 if (job->completion_cb) 147 job->input = NULL;
204 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, ev->status); 148
149 efl_del(job->output);
150 job->output = NULL;
151
152 job->completion_cb = NULL;
153 job->progress_cb = NULL;
154 job->data = NULL;
205 155
206 _job_list = eina_list_remove(_job_list, job); 156 _job_list = eina_list_remove(_job_list, job);
207 free(job->dst);
208 ecore_con_url_free(job->url_con);
209 free(job); 157 free(job);
210
211 return ECORE_CALLBACK_DONE;
212} 158}
213 159
160EFL_CALLBACKS_ARRAY_DEFINE(ecore_file_download_copier_cbs,
161 { EFL_IO_COPIER_EVENT_DONE, _ecore_file_download_copier_done },
162 { EFL_IO_COPIER_EVENT_ERROR, _ecore_file_download_copier_error },
163 { EFL_IO_COPIER_EVENT_PROGRESS, _ecore_file_download_copier_progress },
164 { EFL_EVENT_DEL, _ecore_file_download_copier_del });
165
214static Eina_Bool 166static Eina_Bool
215_ecore_file_download_url_progress_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event) 167_ecore_file_download_headers_foreach_cb(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, void *fdata)
216{ 168{
217/* this reports the downloads progress. if we return 0, then download 169 Ecore_File_Download_Job *job = fdata;
218 * continues, if we return anything else, then the download stops */ 170
219 Ecore_Con_Event_Url_Progress *ev = event; 171 efl_net_dialer_http_request_header_add(job->input, key, data);
220 Ecore_File_Download_Job *job; 172
221 173 return EINA_TRUE;
222 job = eina_list_search_unsorted(_job_list, _ecore_file_download_url_compare_job, ev->url_con);
223 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB)) return ECORE_CALLBACK_PASS_ON;
224
225 if (job->progress_cb)
226 if (job->progress_cb(ecore_con_url_data_get(job->url_con), job->dst,
227 (long int) ev->down.total, (long int) ev->down.now,
228 (long int) ev->up.total, (long int) ev->up.now) != 0)
229 {
230 _job_list = eina_list_remove(_job_list, job);
231 fclose(job->file);
232 free(job->dst);
233 free(job);
234
235 return ECORE_CALLBACK_PASS_ON;
236 }
237
238 return ECORE_CALLBACK_DONE;
239} 174}
240 175
241Ecore_File_Download_Job * 176EAPI Eina_Bool
242_ecore_file_download_curl(const char *url, const char *dst, 177ecore_file_download_full(const char *url,
243 Ecore_File_Download_Completion_Cb completion_cb, 178 const char *dst,
244 Ecore_File_Download_Progress_Cb progress_cb, 179 Ecore_File_Download_Completion_Cb completion_cb,
245 void *data, 180 Ecore_File_Download_Progress_Cb progress_cb,
246 Eina_Hash *headers) 181 void *data,
182 Ecore_File_Download_Job **job_ret,
183 Eina_Hash *headers)
247{ 184{
248 Ecore_File_Download_Job *job; 185 Ecore_File_Download_Job *job;
186 Eina_Error err;
187 Eo *loop;
188 char *dir;
249 189
250 job = calloc(1, sizeof(Ecore_File_Download_Job)); 190 if (job_ret) *job_ret = NULL;
251 if (!job) return NULL; 191 if (!url)
252 192 {
253 ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB); 193 CRI("Download URL is null");
194 return EINA_FALSE;
195 }
254 196
255 job->file = fopen(dst, "wb"); 197 dir = ecore_file_dir_get(dst);
256 if (!job->file) 198 if (!ecore_file_is_dir(dir))
257 { 199 {
258 free(job); 200 ERR("%s is not a directory", dir);
259 return NULL; 201 free(dir);
202 return EINA_FALSE;
260 } 203 }
261 job->url_con = ecore_con_url_new(url); 204 free(dir);
262 if (!job->url_con) 205 if (ecore_file_exists(dst))
263 { 206 {
264 fclose(job->file); 207 ERR("%s already exists", dst);
265 free(job); 208 return EINA_FALSE;
266 return NULL;
267 } 209 }
268 210
269 if (headers) eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job); 211 loop = ecore_main_loop_get();
270 ecore_con_url_fd_set(job->url_con, fileno(job->file)); 212 EINA_SAFETY_ON_NULL_RETURN_VAL(loop, EINA_FALSE);
271 ecore_con_url_data_set(job->url_con, data); 213
214 job = calloc(1, sizeof(Ecore_File_Download_Job));
215 EINA_SAFETY_ON_NULL_RETURN_VAL(job, EINA_FALSE);
216 ECORE_MAGIC_SET(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB);
217
218 job->input = efl_add(EFL_NET_DIALER_HTTP_CLASS, loop,
219 efl_net_dialer_http_allow_redirects_set(efl_added, EINA_TRUE));
220 EINA_SAFETY_ON_NULL_GOTO(job->input, error_input);
221
222 job->output = efl_add(EFL_IO_FILE_CLASS, loop,
223 efl_file_set(efl_added, dst, NULL),
224 efl_io_file_flags_set(efl_added, O_WRONLY | O_CREAT),
225 efl_io_closer_close_on_exec_set(efl_added, EINA_TRUE),
226 efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE),
227 efl_io_file_mode_set(efl_added, 0644));
228 EINA_SAFETY_ON_NULL_GOTO(job->output, error_output);
229
230 job->copier = efl_add(EFL_IO_COPIER_CLASS, loop,
231 efl_io_copier_source_set(efl_added, job->input),
232 efl_io_copier_destination_set(efl_added, job->output),
233 efl_io_closer_close_on_destructor_set(efl_added, EINA_TRUE),
234 efl_event_callback_array_add(efl_added, ecore_file_download_copier_cbs(), job));
235 EINA_SAFETY_ON_NULL_GOTO(job->copier, error_copier);
236
237 _job_list = eina_list_append(_job_list, job);
272 238
273 job->dst = strdup(dst); 239 if (headers)
240 eina_hash_foreach(headers, _ecore_file_download_headers_foreach_cb, job);
274 241
275 job->completion_cb = completion_cb; 242 job->completion_cb = completion_cb;
276 job->progress_cb = progress_cb; 243 job->progress_cb = progress_cb;
277 _job_list = eina_list_append(_job_list, job); 244 job->data = data;
278 245
279 if (!ecore_con_url_get(job->url_con)) 246 err = efl_net_dialer_dial(job->input, url);
247 if (err)
280 { 248 {
281 ecore_con_url_free(job->url_con); 249 ERR("Could not download %s: %s", url, eina_error_msg_get(err));
282 _job_list = eina_list_remove(_job_list, job); 250 goto error_dial;
283 fclose(job->file);
284 ecore_file_remove(job->dst);
285 free(job->dst);
286 free(job);
287 return NULL;
288 } 251 }
289 252
290 return job; 253 if (job_ret) *job_ret = job;
254 return EINA_TRUE;
255
256 error_dial:
257 efl_del(job->copier);
258 return EINA_FALSE; /* copier's "del" event will delete everything else */
259
260 error_copier:
261 efl_del(job->output);
262 error_output:
263 efl_del(job->input);
264 error_input:
265 ECORE_MAGIC_SET(job, ECORE_MAGIC_NONE);
266 free(job);
267 return EINA_FALSE;
268}
269
270EAPI Eina_Bool
271ecore_file_download(const char *url,
272 const char *dst,
273 Ecore_File_Download_Completion_Cb completion_cb,
274 Ecore_File_Download_Progress_Cb progress_cb,
275 void *data,
276 Ecore_File_Download_Job **job_ret)
277{
278 return ecore_file_download_full(url, dst, completion_cb, progress_cb, data, job_ret, NULL);
279}
280
281EAPI Eina_Bool
282ecore_file_download_protocol_available(const char *protocol)
283{
284 if (!strncmp(protocol, "file://", 7)) return EINA_TRUE;
285 else if (!strncmp(protocol, "http://", 7)) return EINA_TRUE;
286 else if (!strncmp(protocol, "https://", 8)) return EINA_TRUE;
287 else if (!strncmp(protocol, "ftp://", 6)) return EINA_TRUE;
288
289 return EINA_FALSE;
291} 290}
292 291
293EAPI void 292EAPI void
@@ -295,14 +294,21 @@ ecore_file_download_abort(Ecore_File_Download_Job *job)
295{ 294{
296 if (!job) 295 if (!job)
297 return; 296 return;
297 if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB))
298 {
299 ECORE_MAGIC_FAIL(job, ECORE_MAGIC_FILE_DOWNLOAD_JOB, __FUNCTION__);
300 return;
301 }
298 302
299 if (job->completion_cb) 303 /* don't call it from _ecore_file_download_copier_done() */
300 job->completion_cb(ecore_con_url_data_get(job->url_con), job->dst, 1); 304 if (job->completion_cb) job->completion_cb = NULL;
301 ecore_con_url_free(job->url_con); 305
302 _job_list = eina_list_remove(_job_list, job); 306 /* efl_io_closer_close()
303 fclose(job->file); 307 * -> _ecore_file_download_copier_done()
304 free(job->dst); 308 * -> efl_del()
305 free(job); 309 * -> _ecore_file_download_copier_del()
310 */
311 efl_io_closer_close(job->copier);
306} 312}
307 313
308EAPI void 314EAPI void