LCOV - code coverage report
Current view: top level - libpkg - fetch_libcurl.c (source / functions) Hit Total Coverage
Test: plop Lines: 146 361 40.4 %
Date: 2024-12-30 07:09:03 Functions: 7 10 70.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 55 198 27.8 %

           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 : }

Generated by: LCOV version 1.15