rpmio/url.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <netinet/in.h>
00008 
00009 #include <rpmmacro.h>
00010 #include <rpmmessages.h>
00011 #include <rpmio_internal.h>
00012 
00013 #include "debug.h"
00014 
00015 /*@access FD_t@*/               /* XXX compared with NULL */
00016 /*@access urlinfo@*/
00017 
00018 #ifndef IPPORT_FTP
00019 #define IPPORT_FTP      21
00020 #endif
00021 #ifndef IPPORT_HTTP
00022 #define IPPORT_HTTP     80
00023 #endif
00024 #ifndef IPPORT_HTTPS
00025 #define IPPORT_HTTPS    443
00026 #endif
00027 #ifndef IPPORT_PGPKEYSERVER
00028 #define IPPORT_PGPKEYSERVER     11371
00029 #endif
00030 
00033 /*@unchecked@*/
00034 int _url_iobuf_size = RPMURL_IOBUF_SIZE;
00035 
00038 /*@unchecked@*/
00039 int _url_debug = 0;
00040 
00041 #define URLDBG(_f, _m, _x)      if ((_url_debug | (_f)) & (_m)) fprintf _x
00042 
00043 #define URLDBGIO(_f, _x)        URLDBG((_f), RPMURL_DEBUG_IO, _x)
00044 #define URLDBGREFS(_f, _x)      URLDBG((_f), RPMURL_DEBUG_REFS, _x)
00045 
00048 /*@unchecked@*/
00049 /*@only@*/ /*@null@*/
00050 urlinfo *_url_cache = NULL;
00051 
00054 /*@unchecked@*/
00055 int _url_count = 0;
00056 
00057 urlinfo XurlLink(urlinfo u, const char *msg, const char *file, unsigned line)
00058 {
00059     URLSANE(u);
00060     u->nrefs++;
00061 /*@-modfilesys@*/
00062 URLDBGREFS(0, (stderr, "--> url %p ++ %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
00063 /*@=modfilesys@*/
00064     /*@-refcounttrans@*/ return u; /*@=refcounttrans@*/
00065 }
00066 
00067 urlinfo XurlNew(const char *msg, const char *file, unsigned line)
00068 {
00069     urlinfo u;
00070     if ((u = xmalloc(sizeof(*u))) == NULL)
00071         return NULL;
00072     memset(u, 0, sizeof(*u));
00073     u->proxyp = -1;
00074     u->port = -1;
00075     u->urltype = URL_IS_UNKNOWN;
00076     u->ctrl = NULL;
00077     u->data = NULL;
00078     u->bufAlloced = 0;
00079     u->buf = NULL;
00080     u->allow = RPMURL_SERVER_HASRANGE;
00081     u->httpVersion = 0;
00082     u->nrefs = 0;
00083     u->magic = URLMAGIC;
00084     return XurlLink(u, msg, file, line);
00085 }
00086 
00087 urlinfo XurlFree(urlinfo u, const char *msg, const char *file, unsigned line)
00088 {
00089     int xx;
00090 
00091     URLSANE(u);
00092 URLDBGREFS(0, (stderr, "--> url %p -- %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
00093     if (--u->nrefs > 0)
00094         /*@-refcounttrans -retalias@*/ return u; /*@=refcounttrans =retalias@*/
00095     if (u->ctrl) {
00096 #ifndef NOTYET
00097         void * fp = fdGetFp(u->ctrl);
00098         /*@-branchstate@*/
00099         if (fp) {
00100             fdPush(u->ctrl, fpio, fp, -1);   /* Push fpio onto stack */
00101             (void) Fclose(u->ctrl);
00102         } else if (fdio->_fileno(u->ctrl) >= 0)
00103             xx = fdio->close(u->ctrl);
00104         /*@=branchstate@*/
00105 #else
00106         (void) Fclose(u->ctrl);
00107 #endif
00108 
00109         u->ctrl = fdio->_fdderef(u->ctrl, "persist ctrl (urlFree)", file, line);
00110         /*@-usereleased@*/
00111         if (u->ctrl)
00112             fprintf(stderr, _("warning: u %p ctrl %p nrefs != 0 (%s %s)\n"),
00113                         u, u->ctrl, (u->host ? u->host : ""),
00114                         (u->scheme ? u->scheme : ""));
00115         /*@=usereleased@*/
00116     }
00117     if (u->data) {
00118 #ifndef NOTYET
00119         void * fp = fdGetFp(u->data);
00120         if (fp) {
00121             fdPush(u->data, fpio, fp, -1);   /* Push fpio onto stack */
00122             (void) Fclose(u->data);
00123         } else if (fdio->_fileno(u->data) >= 0)
00124             xx = fdio->close(u->data);
00125 #else
00126         (void) Fclose(u->ctrl);
00127 #endif
00128 
00129         u->data = fdio->_fdderef(u->data, "persist data (urlFree)", file, line);
00130         /*@-usereleased@*/
00131         if (u->data)
00132             fprintf(stderr, _("warning: u %p data %p nrefs != 0 (%s %s)\n"),
00133                         u, u->data, (u->host ? u->host : ""),
00134                         (u->scheme ? u->scheme : ""));
00135         /*@=usereleased@*/
00136     }
00137     xx = davFree(u);
00138     u->buf = _free(u->buf);
00139     u->url = _free(u->url);
00140     u->scheme = _free((void *)u->scheme);
00141     u->user = _free((void *)u->user);
00142     u->password = _free((void *)u->password);
00143     u->host = _free((void *)u->host);
00144     u->portstr = _free((void *)u->portstr);
00145     u->proxyu = _free((void *)u->proxyu);
00146     u->proxyh = _free((void *)u->proxyh);
00147 
00148     /*@-refcounttrans@*/ u = _free(u); /*@-refcounttrans@*/
00149     return NULL;
00150 }
00151 
00152 /*@-boundswrite@*/
00153 void urlFreeCache(void)
00154 {
00155     if (_url_cache) {
00156         int i;
00157         for (i = 0; i < _url_count; i++) {
00158             if (_url_cache[i] == NULL) continue;
00159             _url_cache[i] = urlFree(_url_cache[i], "_url_cache");
00160             if (_url_cache[i])
00161                 fprintf(stderr,
00162                         _("warning: _url_cache[%d] %p nrefs(%d) != 1 (%s %s)\n"),
00163                         i, _url_cache[i], _url_cache[i]->nrefs,
00164                         (_url_cache[i]->host ? _url_cache[i]->host : ""),
00165                         (_url_cache[i]->scheme ? _url_cache[i]->scheme : ""));
00166         }
00167     }
00168     _url_cache = _free(_url_cache);
00169     _url_count = 0;
00170 }
00171 /*@=boundswrite@*/
00172 
00173 static int urlStrcmp(/*@null@*/ const char * str1, /*@null@*/ const char * str2)
00174         /*@*/
00175 {
00176     if (str1)
00177         if (str2)
00178             return strcmp(str1, str2);
00179     if (str1 != str2)
00180         return -1;
00181     return 0;
00182 }
00183 
00184 /*@-boundswrite@*/
00185 /*@-mods@*/
00186 static void urlFind(/*@null@*/ /*@in@*/ /*@out@*/ urlinfo * uret, int mustAsk)
00187         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00188         /*@modifies *uret, rpmGlobalMacroContext, fileSystem, internalState @*/
00189 {
00190     urlinfo u;
00191     int ucx;
00192     int i = 0;
00193 
00194     if (uret == NULL)
00195         return;
00196 
00197     u = *uret;
00198     URLSANE(u);
00199 
00200     ucx = -1;
00201     for (i = 0; i < _url_count; i++) {
00202         urlinfo ou = NULL;
00203         if (_url_cache == NULL || (ou = _url_cache[i]) == NULL) {
00204             if (ucx < 0)
00205                 ucx = i;
00206             continue;
00207         }
00208 
00209         /* Check for cache-miss condition. A cache miss is
00210          *    a) both items are not NULL and don't compare.
00211          *    b) either of the items is not NULL.
00212          */
00213         if (urlStrcmp(u->scheme, ou->scheme))
00214             continue;
00215         if (urlStrcmp(u->host, ou->host))
00216             continue;
00217         if (urlStrcmp(u->user, ou->user))
00218             continue;
00219         if (urlStrcmp(u->portstr, ou->portstr))
00220             continue;
00221         break;  /* Found item in cache */
00222     }
00223 
00224     if (i == _url_count) {
00225         if (ucx < 0) {
00226             ucx = _url_count++;
00227             _url_cache = xrealloc(_url_cache, sizeof(*_url_cache) * _url_count);
00228         }
00229         if (_url_cache)         /* XXX always true */
00230             _url_cache[ucx] = urlLink(u, "_url_cache (miss)");
00231         u = urlFree(u, "urlSplit (urlFind miss)");
00232     } else {
00233         ucx = i;
00234         u = urlFree(u, "urlSplit (urlFind hit)");
00235     }
00236 
00237     /* This URL is now cached. */
00238 
00239     if (_url_cache)             /* XXX always true */
00240         u = urlLink(_url_cache[ucx], "_url_cache");
00241     *uret = u;
00242     /*@-usereleased@*/
00243     u = urlFree(u, "_url_cache (urlFind)");
00244     /*@=usereleased@*/
00245 
00246     /* Zap proxy host and port in case they have been reset */
00247     u->proxyp = -1;
00248     u->proxyh = _free(u->proxyh);
00249 
00250     /* Perform one-time FTP initialization */
00251     if (u->urltype == URL_IS_FTP) {
00252 
00253         if (mustAsk || (u->user != NULL && u->password == NULL)) {
00254             const char * host = (u->host ? u->host : "");
00255             const char * user = (u->user ? u->user : "");
00256             char * prompt;
00257             prompt = alloca(strlen(host) + strlen(user) + 256);
00258             sprintf(prompt, _("Password for %s@%s: "), user, host);
00259             u->password = _free(u->password);
00260 /*@-dependenttrans -moduncon @*/
00261             u->password = Getpass(prompt);
00262 /*@=dependenttrans =moduncon @*/
00263             if (u->password)
00264                 u->password = xstrdup(u->password);
00265         }
00266 
00267         if (u->proxyh == NULL) {
00268             const char *proxy = rpmExpand("%{_ftpproxy}", NULL);
00269             if (proxy && *proxy != '%') {
00270 /*@observer@*/
00271                 const char * host = (u->host ? u->host : "");
00272                 const char *uu = (u->user ? u->user : "anonymous");
00273                 char *nu = xmalloc(strlen(uu) + sizeof("@") + strlen(host));
00274                 (void) stpcpy( stpcpy( stpcpy(nu, uu), "@"), host);
00275                 u->proxyu = nu;
00276                 u->proxyh = xstrdup(proxy);
00277             }
00278             proxy = _free(proxy);
00279         }
00280 
00281         if (u->proxyp < 0) {
00282             const char *proxy = rpmExpand("%{_ftpport}", NULL);
00283             if (proxy && *proxy != '%') {
00284                 char *end = NULL;
00285                 int port = strtol(proxy, &end, 0);
00286                 if (!(end && *end == '\0')) {
00287                     fprintf(stderr, _("error: %sport must be a number\n"),
00288                         (u->scheme ? u->scheme : ""));
00289                     return;
00290                 }
00291                 u->proxyp = port;
00292             }
00293             proxy = _free(proxy);
00294         }
00295     }
00296 
00297     /* Perform one-time HTTP initialization */
00298     if (u->urltype == URL_IS_HTTP || u->urltype == URL_IS_HTTPS || u->urltype == URL_IS_HKP) {
00299 
00300         if (u->proxyh == NULL) {
00301             const char *proxy = rpmExpand("%{_httpproxy}", NULL);
00302             if (proxy && *proxy != '%')
00303                 u->proxyh = xstrdup(proxy);
00304             proxy = _free(proxy);
00305         }
00306 
00307         if (u->proxyp < 0) {
00308             const char *proxy = rpmExpand("%{_httpport}", NULL);
00309             if (proxy && *proxy != '%') {
00310                 char *end;
00311                 int port = strtol(proxy, &end, 0);
00312                 if (!(end && *end == '\0')) {
00313                     fprintf(stderr, _("error: %sport must be a number\n"),
00314                         (u->scheme ? u->scheme : ""));
00315                     return;
00316                 }
00317                 u->proxyp = port;
00318             }
00319             proxy = _free(proxy);
00320         }
00321 
00322     }
00323 
00324     return;
00325 }
00326 /*@=mods@*/
00327 /*@=boundswrite@*/
00328 
00331 /*@observer@*/ /*@unchecked@*/
00332 static struct urlstring {
00333 /*@observer@*/ /*@null@*/
00334     const char * leadin;
00335     urltype     ret;
00336 } urlstrings[] = {
00337     { "file://",        URL_IS_PATH },
00338     { "ftp://",         URL_IS_FTP },
00339     { "hkp://",         URL_IS_HKP },
00340     { "http://",        URL_IS_HTTP },
00341     { "https://",       URL_IS_HTTPS },
00342     { "-",              URL_IS_DASH },
00343     { NULL,             URL_IS_UNKNOWN }
00344 };
00345 
00346 urltype urlIsURL(const char * url)
00347 {
00348     struct urlstring *us;
00349 
00350 /*@-boundsread@*/
00351     if (url && *url) {
00352         for (us = urlstrings; us->leadin != NULL; us++) {
00353             if (strncmp(url, us->leadin, strlen(us->leadin)))
00354                 continue;
00355             return us->ret;
00356         }
00357     }
00358 /*@=boundsread@*/
00359 
00360     return URL_IS_UNKNOWN;
00361 }
00362 
00363 /*@-boundswrite@*/
00364 /* Return path portion of url (or pointer to NUL if url == NULL) */
00365 urltype urlPath(const char * url, const char ** pathp)
00366 {
00367     const char *path;
00368     int urltype;
00369 
00370     path = url;
00371     urltype = urlIsURL(url);
00372     /*@-branchstate@*/
00373     switch (urltype) {
00374     case URL_IS_FTP:
00375         url += sizeof("ftp://") - 1;
00376         path = strchr(url, '/');
00377         if (path == NULL) path = url + strlen(url);
00378         break;
00379     case URL_IS_PATH:
00380         url += sizeof("file://") - 1;
00381         path = strchr(url, '/');
00382         if (path == NULL) path = url + strlen(url);
00383         break;
00384     case URL_IS_HKP:
00385         url += sizeof("hkp://") - 1;
00386         path = strchr(url, '/');
00387         if (path == NULL) path = url + strlen(url);
00388         break;
00389     case URL_IS_HTTP:
00390         url += sizeof("http://") - 1;
00391         path = strchr(url, '/');
00392         if (path == NULL) path = url + strlen(url);
00393         break;
00394     case URL_IS_HTTPS:
00395         url += sizeof("https://") - 1;
00396         path = strchr(url, '/');
00397         if (path == NULL) path = url + strlen(url);
00398         break;
00399     case URL_IS_UNKNOWN:
00400         if (path == NULL) path = "";
00401         break;
00402     case URL_IS_DASH:
00403         path = "";
00404         break;
00405     }
00406     /*@=branchstate@*/
00407     if (pathp)
00408         /*@-observertrans@*/
00409         *pathp = path;
00410         /*@=observertrans@*/
00411     return urltype;
00412 }
00413 /*@=boundswrite@*/
00414 
00415 /*
00416  * Split URL into components. The URL can look like
00417  *      scheme://user:password@host:port/path
00418   * or as in RFC2732 for IPv6 address
00419   *    service://user:password@[ip:v6:ad:dr:es:s]:port/path
00420  */
00421 /*@-bounds@*/
00422 /*@-modfilesys@*/
00423 int urlSplit(const char * url, urlinfo *uret)
00424 {
00425     urlinfo u;
00426     char *myurl;
00427     char *s, *se, *f, *fe;
00428 
00429     if (uret == NULL)
00430         return -1;
00431     if ((u = urlNew("urlSplit")) == NULL)
00432         return -1;
00433 
00434     if ((se = s = myurl = xstrdup(url)) == NULL) {
00435         u = urlFree(u, "urlSplit (error #1)");
00436         return -1;
00437     }
00438 
00439     u->url = xstrdup(url);
00440     u->urltype = urlIsURL(url);
00441 
00442     while (1) {
00443         /* Point to end of next item */
00444         while (*se && *se != '/') se++;
00445         /* Item was scheme. Save scheme and go for the rest ...*/
00446         if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
00447                 se[-1] = '\0';
00448             u->scheme = xstrdup(s);
00449             se += 2;    /* skip over "//" */
00450             s = se++;
00451             continue;
00452         }
00453         
00454         /* Item was everything-but-path. Continue parse on rest */
00455         *se = '\0';
00456         break;
00457     }
00458 
00459     /* Look for ...@host... */
00460     fe = f = s;
00461     while (*fe && *fe != '@') fe++;
00462     /*@-branchstate@*/
00463     if (*fe == '@') {
00464         s = fe + 1;
00465         *fe = '\0';
00466         /* Look for user:password@host... */
00467         while (fe > f && *fe != ':') fe--;
00468         if (*fe == ':') {
00469             *fe++ = '\0';
00470             u->password = xstrdup(fe);
00471         }
00472         u->user = xstrdup(f);
00473     }
00474     /*@=branchstate@*/
00475 
00476     /* Look for ...host:port or [v6addr]:port*/
00477     fe = f = s;
00478     if (strchr(fe, '[') && strchr(fe, ']'))
00479     {
00480             fe = strchr(f, ']');
00481             *f++ = '\0';
00482             *fe++ = '\0';
00483     }
00484     while (*fe && *fe != ':') fe++;
00485     if (*fe == ':') {
00486         *fe++ = '\0';
00487         u->portstr = xstrdup(fe);
00488         if (u->portstr != NULL && u->portstr[0] != '\0') {
00489             char *end;
00490             u->port = strtol(u->portstr, &end, 0);
00491             if (!(end && *end == '\0')) {
00492                 rpmMessage(RPMMESS_ERROR, _("url port must be a number\n"));
00493                 myurl = _free(myurl);
00494                 u = urlFree(u, "urlSplit (error #3)");
00495                 return -1;
00496             }
00497         }
00498     }
00499     u->host = xstrdup(f);
00500 
00501     if (u->port < 0 && u->scheme != NULL) {
00502         struct servent *serv;
00503 /*@-multithreaded -moduncon @*/
00504         /* HACK hkp:// might lookup "pgpkeyserver" */
00505         serv = getservbyname(u->scheme, "tcp");
00506 /*@=multithreaded =moduncon @*/
00507         if (serv != NULL)
00508             u->port = ntohs(serv->s_port);
00509         else if (u->urltype == URL_IS_FTP)
00510             u->port = IPPORT_FTP;
00511         else if (u->urltype == URL_IS_HKP)
00512             u->port = IPPORT_PGPKEYSERVER;
00513         else if (u->urltype == URL_IS_HTTP)
00514             u->port = IPPORT_HTTP;
00515         else if (u->urltype == URL_IS_HTTPS)
00516             u->port = IPPORT_HTTPS;
00517     }
00518 
00519     myurl = _free(myurl);
00520     if (uret) {
00521         *uret = u;
00522 /*@-globs -mods @*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
00523         urlFind(uret, 0);
00524 /*@=globs =mods @*/
00525     }
00526     return 0;
00527 }
00528 /*@=modfilesys@*/
00529 /*@=bounds@*/
00530 
00531 int urlGetFile(const char * url, const char * dest)
00532 {
00533     int rc;
00534     FD_t sfd = NULL;
00535     FD_t tfd = NULL;
00536     const char * sfuPath = NULL;
00537     int urlType = urlPath(url, &sfuPath);
00538 
00539     if (*sfuPath == '\0')
00540         return FTPERR_UNKNOWN;
00541         
00542     sfd = Fopen(url, "r");
00543     if (sfd == NULL || Ferror(sfd)) {
00544         rpmMessage(RPMMESS_DEBUG, _("failed to open %s: %s\n"), url, Fstrerror(sfd));
00545         rc = FTPERR_UNKNOWN;
00546         goto exit;
00547     }
00548 
00549     if (dest == NULL) {
00550         if ((dest = strrchr(sfuPath, '/')) != NULL)
00551             dest++;
00552         else
00553             dest = sfuPath;
00554     }
00555 
00556     if (dest == NULL)
00557         return FTPERR_UNKNOWN;
00558 
00559     /* XXX this can fail if directory in path does not exist. */
00560     tfd = Fopen(dest, "w");
00561 if (_url_debug)
00562 fprintf(stderr, "*** urlGetFile sfd %p %s tfd %p %s\n", sfd, url, (tfd ? tfd : NULL), dest);
00563     if (tfd == NULL || Ferror(tfd)) {
00564         rpmMessage(RPMMESS_DEBUG, _("failed to create %s: %s\n"), dest, Fstrerror(tfd));
00565         rc = FTPERR_UNKNOWN;
00566         goto exit;
00567     }
00568 
00569     switch (urlType) {
00570     case URL_IS_HTTPS:
00571     case URL_IS_HTTP:
00572     case URL_IS_HKP:
00573     case URL_IS_FTP:
00574     case URL_IS_PATH:
00575     case URL_IS_DASH:
00576     case URL_IS_UNKNOWN:
00577         if ((rc = ufdGetFile(sfd, tfd))) {
00578             (void) Unlink(dest);
00579             /* XXX FIXME: sfd possibly closed by copyData */
00580             /*@-usereleased@*/ (void) Fclose(sfd) /*@=usereleased@*/ ;
00581         }
00582         sfd = NULL;     /* XXX Fclose(sfd) done by ufdGetFile */
00583         break;
00584     default:
00585         rc = FTPERR_UNKNOWN;
00586         break;
00587     }
00588 
00589 exit:
00590     if (tfd)
00591         (void) Fclose(tfd);
00592     if (sfd)
00593         (void) Fclose(sfd);
00594 
00595     return rc;
00596 }

Generated on Fri Sep 7 01:27:58 2007 for rpm by  doxygen 1.5.1