LCOV - code coverage report
Current view: top level - external/libfetch - fetch.c (source / functions) Hit Total Coverage
Test: rapport Lines: 66 220 30.0 %
Date: 2021-12-10 16:22:55 Functions: 3 15 20.0 %
Branches: 53 166 31.9 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * SPDX-License-Identifier: BSD-3-Clause
       3                 :            :  *
       4                 :            :  * Copyright (c) 1998-2004 Dag-Erling Smørgrav
       5                 :            :  * All rights reserved.
       6                 :            :  *
       7                 :            :  * Redistribution and use in source and binary forms, with or without
       8                 :            :  * modification, are permitted provided that the following conditions
       9                 :            :  * are met:
      10                 :            :  * 1. Redistributions of source code must retain the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer
      12                 :            :  *    in this position and unchanged.
      13                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      14                 :            :  *    notice, this list of conditions and the following disclaimer in the
      15                 :            :  *    documentation and/or other materials provided with the distribution.
      16                 :            :  * 3. The name of the author may not be used to endorse or promote products
      17                 :            :  *    derived from this software without specific prior written permission
      18                 :            :  *
      19                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
      20                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      21                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      22                 :            :  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
      23                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      24                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      25                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      26                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      27                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      28                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      29                 :            :  */
      30                 :            : 
      31                 :            : #include <sys/cdefs.h>
      32                 :            : #include "bsd_compat.h"
      33                 :            : __FBSDID("$FreeBSD: head/lib/libfetch/fetch.c 357212 2020-01-28 18:37:18Z gordon $");
      34                 :            : 
      35                 :            : #include <sys/param.h>
      36                 :            : 
      37                 :            : #include <netinet/in.h>
      38                 :            : 
      39                 :            : #include <errno.h>
      40                 :            : #include <ctype.h>
      41                 :            : #include <stdio.h>
      42                 :            : #include <stdlib.h>
      43                 :            : #include <string.h>
      44                 :            : 
      45                 :            : #include "fetch.h"
      46                 :            : #include "common.h"
      47                 :            : 
      48                 :            : auth_t   fetchAuthMethod;
      49                 :            : int      fetchLastErrCode;
      50                 :            : char     fetchLastErrString[MAXERRSTRING];
      51                 :            : int      fetchTimeout;
      52                 :            : int      fetchRestartCalls = 1;
      53                 :            : int      fetchDebug;
      54                 :            : 
      55                 :            : 
      56                 :            : /*** Local data **************************************************************/
      57                 :            : 
      58                 :            : /*
      59                 :            :  * Error messages for parser errors
      60                 :            :  */
      61                 :            : #define URL_MALFORMED           1
      62                 :            : #define URL_BAD_SCHEME          2
      63                 :            : #define URL_BAD_PORT            3
      64                 :            : static struct fetcherr url_errlist[] = {
      65                 :            :         { URL_MALFORMED,        FETCH_URL,      "Malformed URL" },
      66                 :            :         { URL_BAD_SCHEME,       FETCH_URL,      "Invalid URL scheme" },
      67                 :            :         { URL_BAD_PORT,         FETCH_URL,      "Invalid server port" },
      68                 :            :         { -1,                   FETCH_UNKNOWN,  "Unknown parser error" }
      69                 :            : };
      70                 :            : 
      71                 :            : 
      72                 :            : /*** Public API **************************************************************/
      73                 :            : 
      74                 :            : /*
      75                 :            :  * Select the appropriate protocol for the URL scheme, and return a
      76                 :            :  * read-only stream connected to the document referenced by the URL.
      77                 :            :  * Also fill out the struct url_stat.
      78                 :            :  */
      79                 :            : FILE *
      80                 :         28 : fetchXGet(struct url *URL, struct url_stat *us, const char *flags)
      81                 :            : {
      82                 :            : 
      83         [ -  + ]:         28 :         if (us != NULL) {
      84                 :         28 :                 us->size = -1;
      85                 :         28 :                 us->atime = us->mtime = 0;
      86                 :         28 :         }
      87         [ +  - ]:         28 :         if (strcmp(URL->scheme, SCHEME_FILE) == 0)
      88                 :          0 :                 return (fetchXGetFile(URL, us, flags));
      89         [ +  - ]:         28 :         else if (strcmp(URL->scheme, SCHEME_FTP) == 0)
      90                 :          0 :                 return (fetchXGetFTP(URL, us, flags));
      91         [ -  + ]:         28 :         else if (strcmp(URL->scheme, SCHEME_HTTP) == 0)
      92                 :         28 :                 return (fetchXGetHTTP(URL, us, flags));
      93         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0)
      94                 :          0 :                 return (fetchXGetHTTP(URL, us, flags));
      95                 :          0 :         url_seterr(URL_BAD_SCHEME);
      96                 :          0 :         return (NULL);
      97                 :         28 : }
      98                 :            : 
      99                 :            : /*
     100                 :            :  * Select the appropriate protocol for the URL scheme, and return a
     101                 :            :  * read-only stream connected to the document referenced by the URL.
     102                 :            :  */
     103                 :            : FILE *
     104                 :          0 : fetchGet(struct url *URL, const char *flags)
     105                 :            : {
     106                 :          0 :         return (fetchXGet(URL, NULL, flags));
     107                 :            : }
     108                 :            : 
     109                 :            : /*
     110                 :            :  * Select the appropriate protocol for the URL scheme, and return a
     111                 :            :  * write-only stream connected to the document referenced by the URL.
     112                 :            :  */
     113                 :            : FILE *
     114                 :          0 : fetchPut(struct url *URL, const char *flags)
     115                 :            : {
     116                 :            : 
     117         [ #  # ]:          0 :         if (strcmp(URL->scheme, SCHEME_FILE) == 0)
     118                 :          0 :                 return (fetchPutFile(URL, flags));
     119         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_FTP) == 0)
     120                 :          0 :                 return (fetchPutFTP(URL, flags));
     121         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTP) == 0)
     122                 :          0 :                 return (fetchPutHTTP(URL, flags));
     123         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0)
     124                 :          0 :                 return (fetchPutHTTP(URL, flags));
     125                 :          0 :         url_seterr(URL_BAD_SCHEME);
     126                 :          0 :         return (NULL);
     127                 :          0 : }
     128                 :            : 
     129                 :            : /*
     130                 :            :  * Select the appropriate protocol for the URL scheme, and return the
     131                 :            :  * size of the document referenced by the URL if it exists.
     132                 :            :  */
     133                 :            : int
     134                 :          0 : fetchStat(struct url *URL, struct url_stat *us, const char *flags)
     135                 :            : {
     136                 :            : 
     137         [ #  # ]:          0 :         if (us != NULL) {
     138                 :          0 :                 us->size = -1;
     139                 :          0 :                 us->atime = us->mtime = 0;
     140                 :          0 :         }
     141         [ #  # ]:          0 :         if (strcmp(URL->scheme, SCHEME_FILE) == 0)
     142                 :          0 :                 return (fetchStatFile(URL, us, flags));
     143         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_FTP) == 0)
     144                 :          0 :                 return (fetchStatFTP(URL, us, flags));
     145         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTP) == 0)
     146                 :          0 :                 return (fetchStatHTTP(URL, us, flags));
     147         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0)
     148                 :          0 :                 return (fetchStatHTTP(URL, us, flags));
     149                 :          0 :         url_seterr(URL_BAD_SCHEME);
     150                 :          0 :         return (-1);
     151                 :          0 : }
     152                 :            : 
     153                 :            : /*
     154                 :            :  * Select the appropriate protocol for the URL scheme, and return a
     155                 :            :  * list of files in the directory pointed to by the URL.
     156                 :            :  */
     157                 :            : struct url_ent *
     158                 :          0 : fetchList(struct url *URL, const char *flags)
     159                 :            : {
     160                 :            : 
     161         [ #  # ]:          0 :         if (strcmp(URL->scheme, SCHEME_FILE) == 0)
     162                 :          0 :                 return (fetchListFile(URL, flags));
     163         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_FTP) == 0)
     164                 :          0 :                 return (fetchListFTP(URL, flags));
     165         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTP) == 0)
     166                 :          0 :                 return (fetchListHTTP(URL, flags));
     167         [ #  # ]:          0 :         else if (strcmp(URL->scheme, SCHEME_HTTPS) == 0)
     168                 :          0 :                 return (fetchListHTTP(URL, flags));
     169                 :          0 :         url_seterr(URL_BAD_SCHEME);
     170                 :          0 :         return (NULL);
     171                 :          0 : }
     172                 :            : 
     173                 :            : /*
     174                 :            :  * Attempt to parse the given URL; if successful, call fetchXGet().
     175                 :            :  */
     176                 :            : FILE *
     177                 :          0 : fetchXGetURL(const char *URL, struct url_stat *us, const char *flags)
     178                 :            : {
     179                 :            :         struct url *u;
     180                 :            :         FILE *f;
     181                 :            : 
     182         [ #  # ]:          0 :         if ((u = fetchParseURL(URL)) == NULL)
     183                 :          0 :                 return (NULL);
     184                 :            : 
     185                 :          0 :         f = fetchXGet(u, us, flags);
     186                 :            : 
     187                 :          0 :         fetchFreeURL(u);
     188                 :          0 :         return (f);
     189                 :          0 : }
     190                 :            : 
     191                 :            : /*
     192                 :            :  * Attempt to parse the given URL; if successful, call fetchGet().
     193                 :            :  */
     194                 :            : FILE *
     195                 :          0 : fetchGetURL(const char *URL, const char *flags)
     196                 :            : {
     197                 :          0 :         return (fetchXGetURL(URL, NULL, flags));
     198                 :            : }
     199                 :            : 
     200                 :            : /*
     201                 :            :  * Attempt to parse the given URL; if successful, call fetchPut().
     202                 :            :  */
     203                 :            : FILE *
     204                 :          0 : fetchPutURL(const char *URL, const char *flags)
     205                 :            : {
     206                 :            :         struct url *u;
     207                 :            :         FILE *f;
     208                 :            : 
     209         [ #  # ]:          0 :         if ((u = fetchParseURL(URL)) == NULL)
     210                 :          0 :                 return (NULL);
     211                 :            : 
     212                 :          0 :         f = fetchPut(u, flags);
     213                 :            : 
     214                 :          0 :         fetchFreeURL(u);
     215                 :          0 :         return (f);
     216                 :          0 : }
     217                 :            : 
     218                 :            : /*
     219                 :            :  * Attempt to parse the given URL; if successful, call fetchStat().
     220                 :            :  */
     221                 :            : int
     222                 :          0 : fetchStatURL(const char *URL, struct url_stat *us, const char *flags)
     223                 :            : {
     224                 :            :         struct url *u;
     225                 :            :         int s;
     226                 :            : 
     227         [ #  # ]:          0 :         if ((u = fetchParseURL(URL)) == NULL)
     228                 :          0 :                 return (-1);
     229                 :            : 
     230                 :          0 :         s = fetchStat(u, us, flags);
     231                 :            : 
     232                 :          0 :         fetchFreeURL(u);
     233                 :          0 :         return (s);
     234                 :          0 : }
     235                 :            : 
     236                 :            : /*
     237                 :            :  * Attempt to parse the given URL; if successful, call fetchList().
     238                 :            :  */
     239                 :            : struct url_ent *
     240                 :          0 : fetchListURL(const char *URL, const char *flags)
     241                 :            : {
     242                 :            :         struct url *u;
     243                 :            :         struct url_ent *ue;
     244                 :            : 
     245         [ #  # ]:          0 :         if ((u = fetchParseURL(URL)) == NULL)
     246                 :          0 :                 return (NULL);
     247                 :            : 
     248                 :          0 :         ue = fetchList(u, flags);
     249                 :            : 
     250                 :          0 :         fetchFreeURL(u);
     251                 :          0 :         return (ue);
     252                 :          0 : }
     253                 :            : 
     254                 :            : /*
     255                 :            :  * Make a URL
     256                 :            :  */
     257                 :            : struct url *
     258                 :          0 : fetchMakeURL(const char *scheme, const char *host, int port, const char *doc,
     259                 :            :     const char *user, const char *pwd)
     260                 :            : {
     261                 :            :         struct url *u;
     262                 :            : 
     263   [ #  #  #  #  :          0 :         if (!scheme || (!host && !doc)) {
                   #  # ]
     264                 :          0 :                 url_seterr(URL_MALFORMED);
     265                 :          0 :                 return (NULL);
     266                 :            :         }
     267                 :            : 
     268   [ #  #  #  # ]:          0 :         if (port < 0 || port > 65535) {
     269                 :          0 :                 url_seterr(URL_BAD_PORT);
     270                 :          0 :                 return (NULL);
     271                 :            :         }
     272                 :            : 
     273                 :            :         /* allocate struct url */
     274         [ #  # ]:          0 :         if ((u = calloc(1, sizeof(*u))) == NULL) {
     275                 :          0 :                 fetch_syserr();
     276                 :          0 :                 return (NULL);
     277                 :            :         }
     278                 :          0 :         u->netrcfd = -1;
     279                 :            : 
     280   [ #  #  #  # ]:          0 :         if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
     281                 :          0 :                 fetch_syserr();
     282                 :          0 :                 free(u);
     283                 :          0 :                 return (NULL);
     284                 :            :         }
     285                 :            : 
     286                 :            : #define seturl(x) snprintf(u->x, sizeof(u->x), "%s", x)
     287                 :          0 :         seturl(scheme);
     288                 :          0 :         seturl(host);
     289                 :          0 :         seturl(user);
     290                 :          0 :         seturl(pwd);
     291                 :            : #undef seturl
     292                 :          0 :         u->port = port;
     293                 :            : 
     294                 :          0 :         return (u);
     295                 :          0 : }
     296                 :            : 
     297                 :            : /*
     298                 :            :  * Return value of the given hex digit.
     299                 :            :  */
     300                 :            : static int
     301                 :          0 : fetch_hexval(char ch)
     302                 :            : {
     303                 :            : 
     304   [ #  #  #  # ]:          0 :         if (ch >= '0' && ch <= '9')
     305                 :          0 :                 return (ch - '0');
     306   [ #  #  #  # ]:          0 :         else if (ch >= 'a' && ch <= 'f')
     307                 :          0 :                 return (ch - 'a' + 10);
     308   [ #  #  #  # ]:          0 :         else if (ch >= 'A' && ch <= 'F')
     309                 :          0 :                 return (ch - 'A' + 10);
     310                 :          0 :         return (-1);
     311                 :          0 : }
     312                 :            : 
     313                 :            : /*
     314                 :            :  * Decode percent-encoded URL component from src into dst, stopping at end
     315                 :            :  * of string, or at @ or : separators.  Returns a pointer to the unhandled
     316                 :            :  * part of the input string (null terminator, @, or :).  No terminator is
     317                 :            :  * written to dst (it is the caller's responsibility).
     318                 :            :  */
     319                 :            : static const char *
     320                 :          0 : fetch_pctdecode(char *dst, const char *src, size_t dlen)
     321                 :            : {
     322                 :            :         int d1, d2;
     323                 :            :         char c;
     324                 :            :         const char *s;
     325                 :            : 
     326   [ #  #  #  #  :          0 :         for (s = src; *s != '\0' && *s != '@' && *s != ':'; s++) {
                   #  # ]
     327   [ #  #  #  #  :          0 :                 if (s[0] == '%' && (d1 = fetch_hexval(s[1])) >= 0 &&
                   #  # ]
     328   [ #  #  #  # ]:          0 :                     (d2 = fetch_hexval(s[2])) >= 0 && (d1 > 0 || d2 > 0)) {
     329                 :          0 :                         c = d1 << 4 | d2;
     330                 :          0 :                         s += 2;
     331                 :          0 :                 } else {
     332                 :          0 :                         c = *s;
     333                 :            :                 }
     334         [ #  # ]:          0 :                 if (dlen-- > 0)
     335                 :          0 :                         *dst++ = c;
     336                 :            :                 else
     337                 :          0 :                         return (NULL);
     338                 :          0 :         }
     339                 :          0 :         return (s);
     340                 :          0 : }
     341                 :            : 
     342                 :            : /*
     343                 :            :  * Split an URL into components. URL syntax is:
     344                 :            :  * [method:/][/[user[:pwd]@]host[:port]/][document]
     345                 :            :  * This almost, but not quite, RFC1738 URL syntax.
     346                 :            :  */
     347                 :            : struct url *
     348                 :       1156 : fetchParseURL(const char *URL)
     349                 :            : {
     350                 :            :         char *doc;
     351                 :            :         const char *p, *q;
     352                 :            :         struct url *u;
     353                 :            :         int i, n;
     354                 :            : 
     355                 :            :         /* allocate struct url */
     356         [ +  - ]:       1156 :         if ((u = calloc(1, sizeof(*u))) == NULL) {
     357                 :          0 :                 fetch_syserr();
     358                 :          0 :                 return (NULL);
     359                 :            :         }
     360                 :       1156 :         u->netrcfd = -1;
     361                 :            : 
     362                 :            :         /* scheme name */
     363         [ +  + ]:       1156 :         if ((p = strstr(URL, ":/"))) {
     364         [ -  + ]:       1044 :                 if (p - URL > URL_SCHEMELEN)
     365                 :          0 :                         goto ouch;
     366         [ +  + ]:       5220 :                 for (i = 0; URL + i < p; i++)
     367                 :       4176 :                         u->scheme[i] = tolower((unsigned char)URL[i]);
     368                 :       1044 :                 URL = ++p;
     369                 :            :                 /*
     370                 :            :                  * Only one slash: no host, leave slash as part of document
     371                 :            :                  * Two slashes: host follows, strip slashes
     372                 :            :                  */
     373         [ -  + ]:       1044 :                 if (URL[1] == '/')
     374                 :       1044 :                         URL = (p += 2);
     375                 :       1044 :         } else {
     376                 :        112 :                 p = URL;
     377                 :            :         }
     378   [ +  +  +  +  :       1156 :         if (!*URL || *URL == '/' || *URL == '.' ||
             +  -  +  + ]
     379         [ -  + ]:         72 :             (u->scheme[0] == '\0' &&
     380         [ #  # ]:          0 :                 strchr(URL, '/') == NULL && strchr(URL, ':') == NULL))
     381                 :       1196 :                 goto nohost;
     382                 :            : 
     383                 :        184 :         p = strpbrk(URL, "/@");
     384   [ +  +  +  - ]:        184 :         if (p && *p == '@') {
     385                 :            :                 /* username */
     386                 :          0 :                 q = fetch_pctdecode(u->user, URL, URL_USERLEN);
     387         [ #  # ]:          0 :                 if (q == NULL)
     388                 :          0 :                         goto ouch;
     389                 :            : 
     390                 :            :                 /* password */
     391         [ #  # ]:          0 :                 if (*q == ':') {
     392                 :          0 :                         q = fetch_pctdecode(u->pwd, q + 1, URL_PWDLEN);
     393         [ #  # ]:          0 :                         if (q == NULL)
     394                 :          0 :                                 goto ouch;
     395                 :          0 :                 }
     396                 :          0 :                 p++;
     397                 :          0 :         } else {
     398                 :        184 :                 p = URL;
     399                 :            :         }
     400                 :            : 
     401                 :            :         /* hostname */
     402         [ -  + ]:        184 :         if (*p == '[') {
     403                 :          0 :                 q = p + 1 + strspn(p + 1, ":0123456789ABCDEFabcdef");
     404         [ #  # ]:          0 :                 if (*q++ != ']')
     405                 :          0 :                         goto ouch;
     406                 :          0 :         } else {
     407                 :            :                 /* valid characters in a DNS name */
     408                 :        184 :                 q = p + strspn(p, "-." "0123456789"
     409                 :            :                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "_"
     410                 :            :                     "abcdefghijklmnopqrstuvwxyz");
     411                 :            :         }
     412   [ +  +  +  +  :        184 :         if ((*q != '\0' && *q != '/' && *q != ':') || q - p > MAXHOSTNAMELEN)
                   +  + ]
     413                 :        112 :                 goto ouch;
     414         [ +  + ]:        656 :         for (i = 0; p + i < q; i++)
     415                 :        584 :                 u->host[i] = tolower((unsigned char)p[i]);
     416                 :         72 :         u->host[i] = '\0';
     417                 :         72 :         p = q;
     418                 :            : 
     419                 :            :         /* port */
     420         [ +  + ]:        128 :         if (*p == ':') {
     421   [ +  +  +  + ]:        336 :                 for (n = 0, q = ++p; *q && (*q != '/'); q++) {
     422   [ +  -  +  -  :        280 :                         if (*q >= '0' && *q <= '9' && n < INT_MAX / 10) {
                   +  - ]
     423                 :        280 :                                 n = n * 10 + (*q - '0');
     424                 :        280 :                         } else {
     425                 :            :                                 /* invalid port */
     426                 :          0 :                                 url_seterr(URL_BAD_PORT);
     427                 :          0 :                                 goto ouch;
     428                 :            :                         }
     429                 :        280 :                 }
     430                 :            :                 /* pkg extension allow for ssh compat */
     431                 :            :                 /*if (n < 1 || n > IPPORT_MAX) */
     432                 :            : #ifndef IPPORT_MAX
     433                 :            : #define IPPORT_MAX 65535
     434                 :            : #endif
     435   [ +  -  +  - ]:         56 :                 if (n < 0 || n > IPPORT_MAX)
     436                 :          0 :                         goto ouch;
     437                 :         56 :                 u->port = n;
     438                 :         56 :                 p = q;
     439                 :         56 :         }
     440                 :            : 
     441                 :            : nohost:
     442                 :            :         /* document */
     443         [ +  + ]:       1044 :         if (!*p)
     444                 :         24 :                 p = "/";
     445                 :            : 
     446   [ +  +  -  + ]:       1044 :         if (strcmp(u->scheme, SCHEME_HTTP) == 0 ||
     447                 :        988 :             strcmp(u->scheme, SCHEME_HTTPS) == 0) {
     448                 :         56 :                 const char hexnums[] = "0123456789abcdef";
     449                 :            : 
     450                 :            :                 /* percent-escape whitespace. */
     451         [ +  - ]:         56 :                 if ((doc = malloc(strlen(p) * 3 + 1)) == NULL) {
     452                 :          0 :                         fetch_syserr();
     453                 :          0 :                         goto ouch;
     454                 :            :                 }
     455                 :         56 :                 u->doc = doc;
     456         [ +  + ]:        460 :                 while (*p != '\0') {
     457         [ -  + ]:        404 :                         if (!isspace((unsigned char)*p)) {
     458                 :        404 :                                 *doc++ = *p++;
     459                 :        404 :                         } else {
     460                 :          0 :                                 *doc++ = '%';
     461                 :          0 :                                 *doc++ = hexnums[((unsigned int)*p) >> 4];
     462                 :          0 :                                 *doc++ = hexnums[((unsigned int)*p) & 0xf];
     463                 :          0 :                                 p++;
     464                 :            :                         }
     465                 :            :                 }
     466                 :         56 :                 *doc = '\0';
     467         [ +  - ]:       1044 :         } else if ((u->doc = strdup(p)) == NULL) {
     468                 :          0 :                 fetch_syserr();
     469                 :          0 :                 goto ouch;
     470                 :            :         }
     471                 :            : 
     472         [ -  + ]:       1044 :         DEBUGF("scheme:   \"%s\"\n"
     473                 :            :             "user:     \"%s\"\n"
     474                 :            :             "password: \"%s\"\n"
     475                 :            :             "host:     \"%s\"\n"
     476                 :            :             "port:     \"%d\"\n"
     477                 :            :             "document: \"%s\"\n",
     478                 :            :             u->scheme, u->user, u->pwd,
     479                 :            :             u->host, u->port, u->doc);
     480                 :            : 
     481                 :       1044 :         return (u);
     482                 :            : 
     483                 :            : ouch:
     484                 :          0 :         free(u);
     485                 :          0 :         return (NULL);
     486                 :       1044 : }
     487                 :            : 
     488                 :            : /*
     489                 :            :  * Free a URL
     490                 :            :  */
     491                 :            : void
     492                 :       1044 : fetchFreeURL(struct url *u)
     493                 :            : {
     494                 :       1044 :         free(u->doc);
     495                 :       1044 :         free(u);
     496                 :       1044 : }

Generated by: LCOV version 1.15