Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2023 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2023 Serenity Cyber Security, LLC <license@futurecrew.ru>
4 : : * Author: Gleb Popov <arrowd@FreeBSD.org>
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions
8 : : * are met:
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer
11 : : * in this position and unchanged.
12 : : * 2. Redistributions in binary form must reproduce the above copyright
13 : : * notice, this list of conditions and the following disclaimer in the
14 : : * documentation and/or other materials provided with the distribution.
15 : : *
16 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
17 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
20 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 : : */
27 : :
28 : : #include <sys/param.h>
29 : : #include <stdlib.h>
30 : : #include <curl/curl.h>
31 : : #include <ctype.h>
32 : :
33 : : #include "pkg.h"
34 : : #include "private/pkg.h"
35 : : #include "private/event.h"
36 : : #include "private/fetch.h"
37 : :
38 : : /*
39 : : * The choice of 2KB/s is arbitrary; at some point this should be configurable.
40 : : */
41 : : #define LIBPKG_SPEED_LIMIT (2 * 1024) /* bytes per second */
42 : :
43 : : struct curl_repodata {
44 : : CURLM *cm;
45 : : CURLU *url;
46 : : };
47 : :
48 : : struct curl_userdata {
49 : : int fd;
50 : : CURL *cl;
51 : : FILE *fh;
52 : : size_t size;
53 : : size_t totalsize;
54 : : size_t content_length;
55 : : bool started;
56 : : const char *url;
57 : : long response;
58 : : };
59 : :
60 : : struct http_mirror {
61 : : CURLU *url;
62 : : struct http_mirror *next;
63 : : };
64 : :
65 : : static
66 : 0 : void dump(const char *text,
67 : : FILE *stream, unsigned char *ptr, size_t size)
68 : : {
69 : : size_t i;
70 : : size_t c;
71 : :
72 : 0 : unsigned int width = 0x40;
73 : :
74 : 0 : fprintf(stream, "%s, %10.10lu bytes (0x%8.8lx)\n",
75 : 0 : text, (unsigned long)size, (unsigned long)size);
76 : :
77 [ # # ]: 0 : for(i = 0; i<size; i += width) {
78 : :
79 : 0 : fprintf(stream, "%4.4lx: ", (unsigned long)i);
80 : :
81 [ # # # # : 0 : for(c = 0; (c < width) && (i + c < size); c++) {
# # ]
82 : : /* check for 0D0A; if found, skip past and start a new line of output */
83 [ # # # # : 0 : if((i + c + 1 < size) && ptr[i + c] == 0x0D &&
# # ]
84 : 0 : ptr[i + c + 1] == 0x0A) {
85 : 0 : i += (c + 2 - width);
86 : 0 : break;
87 : : }
88 : 0 : fprintf(stream, "%c",
89 [ # # # # ]: 0 : (ptr[i + c] >= 0x20) && (ptr[i + c]<0x80)?ptr[i + c]:'.');
90 : : /* check again for 0D0A, to avoid an extra \n if it's at width */
91 [ # # # # : 0 : if((i + c + 2 < size) && ptr[i + c + 1] == 0x0D &&
# # ]
92 : 0 : ptr[i + c + 2] == 0x0A) {
93 : 0 : i += (c + 3 - width);
94 : 0 : break;
95 : : }
96 : 0 : }
97 : 0 : fputc('\n', stream); /* newline */
98 : 0 : }
99 : 0 : fflush(stream);
100 : 0 : }
101 : :
102 : : static
103 : 0 : int my_trace(CURL *handle, curl_infotype type,
104 : : char *data, size_t size,
105 : : void *userp __unused)
106 : : {
107 : : const char *text;
108 : 0 : (void)handle; /* prevent compiler warning */
109 : :
110 [ # # # # : 0 : switch(type) {
# # # # ]
111 : : case CURLINFO_TEXT:
112 : 0 : fprintf(stderr, "== Info: %s", data);
113 : : /* FALLTHROUGH */
114 : : default: /* in case a new one is introduced to shock us */
115 : 0 : return 0;
116 : :
117 : : case CURLINFO_HEADER_OUT:
118 : 0 : text = "=> Send header";
119 : 0 : break;
120 : : case CURLINFO_DATA_OUT:
121 : 0 : text = "=> Send data";
122 : 0 : break;
123 : : case CURLINFO_SSL_DATA_OUT:
124 : 0 : text = "=> Send SSL data";
125 : 0 : break;
126 : : case CURLINFO_HEADER_IN:
127 : 0 : text = "<= Recv header";
128 : 0 : break;
129 : : case CURLINFO_DATA_IN:
130 : 0 : text = "<= Recv data";
131 : 0 : break;
132 : : case CURLINFO_SSL_DATA_IN:
133 : 0 : text = "<= Recv SSL data";
134 : 0 : break;
135 : : }
136 : :
137 : 0 : dump(text, stderr, (unsigned char *)data, size);
138 : 0 : return 0;
139 : 0 : }
140 : :
141 : : static long
142 : 11 : curl_do_fetch(struct curl_userdata *data, CURL *cl, struct curl_repodata *cr)
143 : : {
144 : : char *tmp;
145 : 11 : int still_running = 1;
146 : : CURLMsg *msg;
147 : : int msg_left;
148 : :
149 : 11 : curl_easy_setopt(cl, CURLOPT_FOLLOWLOCATION, 1L);
150 : 11 : curl_easy_setopt(cl, CURLOPT_PRIVATE, &data);
151 : :
152 [ - + # # ]: 11 : if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1)
153 : 0 : curl_easy_setopt(cl, CURLOPT_VERBOSE, 1L);
154 [ - + # # ]: 11 : if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1)
155 : 0 : curl_easy_setopt(cl, CURLOPT_DEBUGFUNCTION, my_trace);
156 : :
157 : : /* compat with libfetch */
158 [ - + ]: 11 : if ((tmp = getenv("HTTP_USER_AGENT")) != NULL)
159 : 11 : curl_easy_setopt(cl, CURLOPT_USERAGENT, tmp);
160 [ + - ]: 11 : if (getenv("SSL_NO_VERIFY_PEER") != NULL)
161 : 0 : curl_easy_setopt(cl, CURLOPT_SSL_VERIFYPEER, 0L);
162 [ + - ]: 11 : if (getenv("SSL_NO_VERIFY_HOSTNAME") != NULL)
163 : 0 : curl_easy_setopt(cl, CURLOPT_SSL_VERIFYHOST, 0L);
164 : 11 : curl_multi_add_handle(cr->cm, cl);
165 : :
166 [ + + ]: 46 : while(still_running) {
167 : 35 : CURLMcode mc = curl_multi_perform(cr->cm, &still_running);
168 : :
169 [ + + ]: 35 : if(still_running)
170 : : /* wait for activity, timeout or "nothing" */
171 : 24 : mc = curl_multi_poll(cr->cm, NULL, 0, 1000, NULL);
172 : :
173 [ - + ]: 35 : if(mc)
174 : 0 : break;
175 : : }
176 : :
177 [ + - ]: 11 : while ((msg = curl_multi_info_read(cr->cm, &msg_left))) {
178 [ - + ]: 11 : if (msg->msg == CURLMSG_DONE) {
179 [ - + ]: 11 : if (msg->data.result == CURLE_ABORTED_BY_CALLBACK)
180 : 0 : return (-1); // FIXME: more clear return code?
181 [ - + ]: 22 : if (msg->data.result == CURLE_COULDNT_CONNECT
182 [ + - ]: 11 : || msg->data.result == CURLE_COULDNT_RESOLVE_HOST
183 [ - + ]: 11 : || msg->data.result == CURLE_COULDNT_RESOLVE_PROXY)
184 : 0 : pkg_emit_pkg_errno(EPKG_NONETWORK, "curl_do_fetch", NULL);
185 : 11 : CURL *eh = msg->easy_handle;
186 : 11 : long rc = 0;
187 : 11 : curl_easy_getinfo(eh, CURLINFO_RESPONSE_CODE, &rc);
188 : 11 : return (rc);
189 : : }
190 : : }
191 : 0 : return (0);
192 : 11 : }
193 : :
194 : : static size_t
195 : 7 : curl_write_cb(char *data, size_t size, size_t nmemb, void *userdata)
196 : : {
197 : 7 : struct curl_userdata *d = (struct curl_userdata *)userdata;
198 : : size_t written;
199 : :
200 : 7 : written = fwrite(data, size, nmemb, d->fh);
201 : 7 : d->size += written;
202 : :
203 : 7 : return (written);
204 : : }
205 : :
206 : : static struct http_mirror *
207 : 0 : http_getmirrors(struct pkg_repo *r, struct curl_repodata *cr)
208 : : {
209 : : CURL *cl;
210 : 0 : struct curl_userdata data = { 0 };
211 : 0 : char *buf = NULL, *walk, *line;
212 : 0 : size_t cap = 0;
213 : 0 : struct http_mirror *m, *mirrors = NULL;
214 : : CURLU *url;
215 : 0 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> fetching http mirror list if any");
216 : :
217 : 0 : cl = curl_easy_init();
218 : 0 : data.fh = open_memstream(& buf, &cap);
219 : 0 : data.cl = cl;
220 : :
221 : 0 : curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, curl_write_cb);
222 : 0 : curl_easy_setopt(cl, CURLOPT_WRITEDATA, &data);
223 : 0 : curl_easy_setopt(cl, CURLOPT_MAXFILESIZE_LARGE, 1048576L);
224 : 0 : curl_easy_setopt(cl, CURLOPT_URL, r->url);
225 : 0 : curl_easy_setopt(cl, CURLOPT_NOPROGRESS, 1L);
226 : 0 : data.url = r->url;
227 [ # # ]: 0 : if (ctx.ip == IPV4)
228 : 0 : curl_easy_setopt(cl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
229 [ # # ]: 0 : if (ctx.ip == IPV6)
230 : 0 : curl_easy_setopt(cl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
231 : 0 : curl_do_fetch(&data, cl, cr);
232 : 0 : fclose(data.fh);
233 : 0 : walk = buf;
234 [ # # ]: 0 : while ((line = strsep(&walk, "\n\r")) != NULL) {
235 [ # # ]: 0 : if (strncmp(line, "URL:", 4) != 0)
236 : 0 : continue;
237 : 0 : line += 4;
238 [ # # ]: 0 : while (isspace(*line))
239 : 0 : line++;
240 [ # # ]: 0 : if (*line == '\0')
241 : 0 : continue;
242 : 0 : url = curl_url();
243 [ # # ]: 0 : if (curl_url_set(url, CURLUPART_URL, line, 0)) {
244 : 0 : curl_url_cleanup(url);
245 : 0 : pkg_emit_error("Invalid mirror url: '%s'", line);
246 : 0 : continue;
247 : : }
248 : 0 : m = xmalloc(sizeof(*m));
249 : 0 : m->url = url;
250 : 0 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> appending an http mirror: %s", line);
251 [ # # # # ]: 0 : LL_APPEND(mirrors, m);
252 : : }
253 : 0 : free(buf);
254 : :
255 : 0 : return (mirrors);
256 : : }
257 : :
258 : : static size_t
259 : 65 : curl_parseheader_cb(void *ptr __unused, size_t size, size_t nmemb, void *userdata)
260 : : {
261 : 65 : struct curl_userdata *d = (struct curl_userdata *)userdata;
262 : :
263 : 65 : curl_easy_getinfo(d->cl, CURLINFO_RESPONSE_CODE, &d->response);
264 [ - + ]: 65 : if (d->response == 404)
265 : 0 : return (CURLE_WRITE_ERROR);
266 [ + + + + ]: 65 : if (d->response == 200 && !d->started) {
267 : 7 : pkg_emit_fetch_begin(d->url);
268 : 7 : pkg_emit_progress_start(NULL);
269 : 7 : d->started = true;
270 : 7 : }
271 : :
272 : 65 : return (size * nmemb);
273 : 65 : }
274 : :
275 : : static int
276 : 136 : curl_progress_cb(void *userdata, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal __unused, curl_off_t ulnow __unused)
277 : : {
278 : 136 : struct curl_userdata *d = (struct curl_userdata *)userdata;
279 : :
280 [ + + ]: 136 : if (d->response != 200)
281 : 104 : return (0);
282 : :
283 : 32 : return pkg_emit_progress_tick(dlnow, dltotal);
284 : 136 : }
285 : :
286 : : int
287 : 11 : curl_open(struct pkg_repo *repo, struct fetch_item *fi __unused)
288 : : {
289 : : struct curl_repodata *cr;
290 : 11 : pkg_dbg(PKG_DBG_FETCH, 2, "curl_open");
291 : :
292 [ + + ]: 11 : if (repo->fetch_priv != NULL)
293 : 6 : return (EPKG_OK);
294 : :
295 : 5 : curl_global_init(CURL_GLOBAL_ALL);
296 : 5 : cr = xcalloc(1, sizeof(*cr));
297 : 5 : cr->cm = curl_multi_init();
298 : 5 : curl_multi_setopt(cr->cm, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
299 : 5 : curl_multi_setopt(cr->cm, CURLMOPT_MAX_HOST_CONNECTIONS, 1);
300 : : /* TODO: Later for parallel fetching */
301 : : /*curl_multi_setopt(cm, CURLMOPT_MAX_HOST_TOTAL_CONNECTIONS, 4);*/
302 : 5 : repo->fetch_priv = cr;
303 [ - + # # ]: 5 : if (repo->mirror_type == SRV && repo->srv == NULL) {
304 : 0 : int urloff = 0;
305 : 0 : cr->url = curl_url();
306 [ # # ]: 0 : if (strncasecmp(repo->url, "pkg+", 4) == 0)
307 : 0 : urloff = 4;
308 : 0 : CURLUcode c = curl_url_set(cr->url, CURLUPART_URL, repo->url + urloff, 0);
309 [ # # ]: 0 : if (c) {
310 : 0 : pkg_emit_error("impossible to parse url: '%s'", repo->url);
311 : 0 : return (EPKG_FATAL);
312 : : }
313 : :
314 : : char *zone;
315 : 0 : char *host = NULL, *scheme = NULL;
316 : 0 : curl_url_get(cr->url, CURLUPART_HOST, &host, 0);
317 : 0 : curl_url_get(cr->url, CURLUPART_SCHEME, &scheme, 0);
318 : 0 : xasprintf(&zone, "_%s._tcp.%s", scheme, host);
319 : 0 : repo->srv = dns_getsrvinfo(zone);
320 : 0 : free(zone);
321 : 0 : free(host);
322 : 0 : free(scheme);
323 [ # # ]: 0 : if (repo->srv == NULL) {
324 : 0 : pkg_emit_error("No SRV record found for the "
325 : 0 : "repo '%s'", repo->name);
326 : 0 : repo->mirror_type = NOMIRROR;
327 : 0 : }
328 : 0 : }
329 [ - + # # ]: 5 : if (repo->mirror_type == HTTP && repo->http == NULL) {
330 [ # # ]: 0 : if (strncasecmp(repo->url, "pkg+", 4) == 0) {
331 : 0 : pkg_emit_error("invalid for http mirror mechanism "
332 : 0 : "scheme '%s'", repo->url);
333 : 0 : return (EPKG_FATAL);
334 : : }
335 : 0 : cr->url = curl_url();
336 : 0 : CURLUcode c = curl_url_set(cr->url, CURLUPART_URL, repo->url, 0);
337 [ # # ]: 0 : if (c) {
338 : 0 : pkg_emit_error("impossible to parse url: '%s'", repo->url);
339 : 0 : return (EPKG_FATAL);
340 : : }
341 : 0 : repo->http = http_getmirrors(repo, cr);
342 [ # # ]: 0 : if (repo->http == NULL) {
343 : 0 : pkg_emit_error("No HTTP mirrors founds for the repo "
344 : 0 : "'%s'", repo->name);
345 : 0 : repo->mirror_type = NOMIRROR;
346 : 0 : }
347 : 0 : }
348 : :
349 : 5 : return (EPKG_OK);
350 : 11 : }
351 : :
352 : : int
353 : 11 : curl_fetch(struct pkg_repo *repo, int dest, struct fetch_item *fi)
354 : : {
355 : : CURL *cl;
356 : 11 : CURLU *hu = NULL;
357 : : CURLcode res;
358 : 11 : struct curl_userdata data = { 0 };
359 : : int64_t retry;
360 : 11 : int retcode = EPKG_OK;
361 : 11 : struct dns_srvinfo *srv_current = NULL;
362 : 11 : struct http_mirror *http_current = NULL;
363 : 11 : char *urlpath = NULL;
364 : 11 : const char *relpath = NULL;
365 : 11 : const char *userpasswd = get_http_auth();
366 : 11 : const char *http_proxy = getenv("HTTP_PROXY");
367 : 11 : const char *http_proxy_auth = getenv("HTTP_PROXY_AUTH");
368 : 11 : const char *sslkey = getenv("SSL_CLIENT_KEY_FILE");
369 : 11 : const char *sslcert = getenv("SSL_CLIENT_CERT_FILE");
370 : 11 : const char *ssl_ca_cert_file = getenv("SSL_CA_CERT_FILE");
371 : 11 : const char *ssl_ca_cert_path = getenv("SSL_CA_CERT_PATH");
372 : 11 : const char *netrc_file = getenv("NETRC");
373 : :
374 : 11 : struct curl_repodata *cr = (struct curl_repodata *)repo->fetch_priv;
375 : :
376 : 11 : data.fh = fdopen(dup(dest), "w");
377 [ + - ]: 11 : if (data.fh == NULL)
378 : 0 : return (EPKG_FATAL);
379 : 11 : data.totalsize = fi->size;
380 : 11 : data.url = fi->url;
381 : :
382 : 11 : pkg_dbg(PKG_DBG_FETCH, 2, "curl> fetching %s\n", fi->url);
383 : 11 : retry = pkg_object_int(pkg_config_get("FETCH_RETRY"));
384 [ + - - + ]: 11 : if (repo->mirror_type == SRV || repo->mirror_type == HTTP) {
385 : 0 : CURLU *cu = curl_url();
386 : 0 : curl_url_set(cu, CURLUPART_URL, fi->url, 0);
387 : 0 : curl_url_get(cu, CURLUPART_PATH, &urlpath, 0);
388 [ # # # # ]: 0 : if (urlpath != NULL && repo->mirror_type == SRV)
389 : 0 : curl_url_set(cr->url, CURLUPART_PATH, urlpath, 0);
390 [ # # # # ]: 0 : if (urlpath != NULL && repo->mirror_type == HTTP) {
391 : 0 : CURLU *ru = curl_url();
392 : 0 : char *doc = NULL;
393 : 0 : curl_url_set(ru, CURLUPART_URL, repo->url, 0);
394 : 0 : curl_url_get(ru, CURLUPART_PATH, &doc, 0);
395 : 0 : relpath = urlpath;
396 [ # # ]: 0 : if (doc != NULL)
397 : 0 : relpath += strlen(doc);
398 : 0 : free(doc);
399 : 0 : curl_url_cleanup(ru);
400 : 0 : }
401 : 0 : curl_url_cleanup(cu);
402 : 0 : }
403 [ - + ]: 22 : if (http_proxy == NULL)
404 : 11 : http_proxy = getenv("http_proxy");
405 : :
406 : : do_retry:
407 : 11 : cl = curl_easy_init();
408 : 11 : data.cl = cl;
409 [ + - ]: 11 : if (repo->mirror_type == SRV) {
410 : : char *portstr;
411 [ # # ]: 0 : if (srv_current != NULL)
412 : 0 : srv_current = srv_current->next;
413 [ # # ]: 0 : if (srv_current == NULL)
414 : 0 : srv_current = repo->srv;
415 : 0 : curl_url_set(cr->url, CURLUPART_HOST, srv_current->host, 0);
416 : 0 : xasprintf(&portstr, "%d", srv_current->port);
417 : 0 : curl_url_set(cr->url, CURLUPART_PORT, portstr, 0);
418 : 0 : free(portstr);
419 : 0 : curl_easy_setopt(cl, CURLOPT_CURLU, cr->url);
420 [ - + ]: 11 : } else if (repo->mirror_type == HTTP) {
421 [ # # ]: 0 : if (http_current != NULL)
422 : 0 : http_current = http_current->next;
423 [ # # ]: 0 : if (http_current == NULL)
424 : 0 : http_current = repo->http;
425 : 0 : char *doc = NULL;
426 : 0 : char *p = NULL;
427 : 0 : const char *path = relpath;;
428 : 0 : curl_url_cleanup(hu);
429 : 0 : hu = curl_url_dup(http_current->url);
430 : 0 : curl_url_get(hu, CURLUPART_PATH, &doc, 0);
431 [ # # ]: 0 : if (doc != NULL) {
432 : 0 : xasprintf(&p, "%s/%s", doc, relpath);
433 : 0 : path = p;
434 : 0 : }
435 : 0 : curl_url_set(hu, CURLUPART_PATH, path, 0);
436 : 0 : free(p);
437 : : char *lurl;
438 : 0 : curl_url_get(hu, CURLUPART_URL, &lurl, 0);
439 : 0 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> new http mirror url: %s", lurl);
440 : 0 : curl_easy_setopt(cl, CURLOPT_CURLU, hu);
441 : 0 : } else {
442 : 11 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> No mirror set url to %s\n", fi->url);
443 : 11 : curl_easy_setopt(cl, CURLOPT_URL, fi->url);
444 : : }
445 [ - + # # ]: 11 : if (ctx.debug_flags & PKG_DBG_FETCH && ctx.debug_level >= 1) {
446 : 0 : const char *lurl = NULL;
447 : 0 : curl_easy_getinfo(cl, CURLINFO_EFFECTIVE_URL, &lurl);
448 [ # # ]: 0 : if (lurl) {
449 : 0 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> attempting to fetch from %s\n", lurl);
450 : 0 : }
451 : 0 : pkg_dbg(PKG_DBG_FETCH, 2, "CURL> retries left: %"PRId64"\n", retry);
452 : 0 : }
453 : 11 : curl_easy_setopt(cl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
454 [ + - ]: 11 : if (userpasswd != NULL) {
455 : 0 : curl_easy_setopt(cl, CURLOPT_USERPWD, userpasswd);
456 : 0 : }
457 [ + - ]: 11 : if (http_proxy != NULL)
458 : 0 : curl_easy_setopt(cl, CURLOPT_PROXY, http_proxy);
459 [ + - ]: 11 : if (http_proxy_auth != NULL) {
460 : 0 : curl_easy_setopt(cl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
461 : 0 : curl_easy_setopt(cl, CURLOPT_PROXYUSERPWD, http_proxy_auth);
462 : 0 : }
463 [ + - ]: 11 : if (sslkey != NULL)
464 : 0 : curl_easy_setopt(cl, CURLOPT_SSLKEY, sslkey);
465 [ + - ]: 11 : if (sslcert != NULL)
466 : 0 : curl_easy_setopt(cl, CURLOPT_SSLCERT, sslcert);
467 [ + - ]: 11 : if (ssl_ca_cert_file != NULL)
468 : 0 : curl_easy_setopt(cl, CURLOPT_CAINFO, ssl_ca_cert_file);
469 [ + - ]: 11 : if (ssl_ca_cert_path != NULL)
470 : 0 : curl_easy_setopt(cl, CURLOPT_CAPATH, ssl_ca_cert_path);
471 [ + - ]: 11 : if (netrc_file != NULL)
472 : 0 : curl_easy_setopt(cl, CURLOPT_NETRC_FILE, netrc_file);
473 : 11 : curl_easy_setopt(cl, CURLOPT_NETRC, 1L);
474 : :
475 [ + - ]: 11 : if (repo->ip == IPV4)
476 : 0 : curl_easy_setopt(cl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
477 [ + - ]: 11 : if (repo->ip == IPV6)
478 : 0 : curl_easy_setopt(cl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
479 : 11 : curl_easy_setopt(cl, CURLOPT_NOPROGRESS, 0L);
480 : 11 : curl_easy_setopt(cl, CURLOPT_WRITEFUNCTION, curl_write_cb);
481 : 11 : curl_easy_setopt(cl, CURLOPT_WRITEDATA, &data);
482 : 11 : curl_easy_setopt(cl, CURLOPT_XFERINFOFUNCTION, curl_progress_cb);
483 : 11 : curl_easy_setopt(cl, CURLOPT_XFERINFODATA, &data);
484 : 11 : curl_easy_setopt(cl, CURLOPT_HEADERFUNCTION, curl_parseheader_cb);
485 : 11 : curl_easy_setopt(cl, CURLOPT_HEADERDATA, &data);
486 : 11 : curl_easy_setopt(cl, CURLOPT_TIMEVALUE_LARGE, (curl_off_t)fi->mtime);
487 : 11 : curl_easy_setopt(cl, CURLOPT_FILETIME, 1L);
488 : 11 : curl_easy_setopt(cl, CURLOPT_TIMECONDITION, (long)CURL_TIMECOND_IFMODSINCE);
489 [ - + ]: 11 : if (repo->fetcher->timeout > 0) {
490 : 11 : curl_easy_setopt(cl, CURLOPT_CONNECTTIMEOUT, repo->fetcher->timeout);
491 : :
492 : 11 : curl_easy_setopt(cl, CURLOPT_LOW_SPEED_LIMIT, LIBPKG_SPEED_LIMIT);
493 : 11 : curl_easy_setopt(cl, CURLOPT_LOW_SPEED_TIME, repo->fetcher->timeout);
494 : 11 : }
495 : :
496 : 11 : long rc = curl_do_fetch(&data, cl, cr);
497 : : curl_off_t t;
498 : 11 : res = curl_easy_getinfo(cl, CURLINFO_FILETIME_T, &t);
499 : 11 : curl_multi_remove_handle(cr->cm, cl);
500 : 11 : curl_easy_cleanup(cl);
501 [ + + ]: 11 : if (rc == 304) {
502 : 4 : retcode = EPKG_UPTODATE;
503 [ - + ]: 11 : } else if (rc == -1) {
504 : 0 : retcode = EPKG_CANCEL;
505 [ + - ]: 7 : } else if (rc != 200) {
506 : 0 : --retry;
507 [ # # ]: 0 : if (retry <= 0) {
508 [ # # ]: 0 : if (rc == 404) {
509 : 0 : retcode = EPKG_ENOENT;
510 : 0 : } else {
511 : 0 : pkg_emit_error("An error occured while fetching package");
512 : 0 : retcode = EPKG_FATAL;
513 : : }
514 : 0 : } else
515 : 0 : goto do_retry;
516 : 0 : }
517 : :
518 [ + - + + ]: 11 : if (res == CURLE_OK && t >= 0) {
519 : 7 : fi->mtime = t;
520 [ - + # # : 11 : } else if (rc != 304 && retcode != EPKG_FATAL &&
# # ]
521 [ # # ]: 0 : retcode != EPKG_CANCEL && retcode != EPKG_ENOENT) {
522 : 0 : pkg_emit_error("Impossible to get the value from Last-Modified"
523 : : " HTTP header");
524 : 0 : fi->mtime = 0;
525 : 0 : }
526 : 11 : fclose(data.fh);
527 : 11 : free(urlpath);
528 : 11 : curl_url_cleanup(hu);
529 : :
530 : 11 : return (retcode);
531 : 11 : }
532 : :
533 : : void
534 : 4 : curl_cleanup(struct pkg_repo *repo)
535 : : {
536 : : struct curl_repodata *cr;
537 : :
538 [ + - ]: 4 : if (repo->fetch_priv == NULL)
539 : 0 : return;
540 : 4 : cr = repo->fetch_priv;
541 : 4 : curl_multi_cleanup(cr->cm);
542 [ + - ]: 4 : if (cr->url != NULL)
543 : 0 : curl_url_cleanup(cr->url);
544 : 4 : repo->fetch_priv = NULL;
545 : 4 : }
|