Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

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 
00027 /*@unchecked@*/
00028 int _url_iobuf_size = RPMURL_IOBUF_SIZE;
00029 
00032 /*@unchecked@*/
00033 int _url_debug = 0;
00034 
00035 #define URLDBG(_f, _m, _x)      if ((_url_debug | (_f)) & (_m)) fprintf _x
00036 
00037 #define URLDBGIO(_f, _x)        URLDBG((_f), RPMURL_DEBUG_IO, _x)
00038 #define URLDBGREFS(_f, _x)      URLDBG((_f), RPMURL_DEBUG_REFS, _x)
00039 
00042 /*@-incondefs@*/
00043 /*@unchecked@*/
00044 /*@only@*/ /*@null@*/
00045 urlinfo *_url_cache = NULL;
00046 /*@=incondefs@*/
00047 
00050 /*@-incondefs@*/
00051 /*@unchecked@*/
00052 int _url_count = 0;
00053 /*@=incondefs@*/
00054 
00060 /*@unused@*/ static inline /*@null@*/ void *
00061 _free(/*@only@*/ /*@null@*/ const void * p) /*@modifies p@*/
00062 {
00063     if (p != NULL)      free((void *)p);
00064     return NULL;
00065 }
00066 
00067 urlinfo XurlLink(urlinfo u, const char *msg, const char *file, unsigned line)
00068 {
00069     URLSANE(u);
00070     u->nrefs++;
00071 /*@-modfilesys@*/
00072 URLDBGREFS(0, (stderr, "--> url %p ++ %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
00073 /*@=modfilesys@*/
00074     /*@-refcounttrans@*/ return u; /*@=refcounttrans@*/
00075 }
00076 
00077 urlinfo XurlNew(const char *msg, const char *file, unsigned line)
00078 {
00079     urlinfo u;
00080     if ((u = xmalloc(sizeof(*u))) == NULL)
00081         return NULL;
00082     memset(u, 0, sizeof(*u));
00083     u->proxyp = -1;
00084     u->port = -1;
00085     u->urltype = URL_IS_UNKNOWN;
00086     u->ctrl = NULL;
00087     u->data = NULL;
00088     u->bufAlloced = 0;
00089     u->buf = NULL;
00090     u->httpHasRange = 1;
00091     u->httpVersion = 0;
00092     u->nrefs = 0;
00093     u->magic = URLMAGIC;
00094     return XurlLink(u, msg, file, line);
00095 }
00096 
00097 urlinfo XurlFree(urlinfo u, const char *msg, const char *file, unsigned line)
00098 {
00099     int xx;
00100 
00101     URLSANE(u);
00102 URLDBGREFS(0, (stderr, "--> url %p -- %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
00103     if (--u->nrefs > 0)
00104         /*@-refcounttrans -retalias@*/ return u; /*@=refcounttrans =retalias@*/
00105     if (u->ctrl) {
00106 #ifndef NOTYET
00107         void * fp = fdGetFp(u->ctrl);
00108         /*@-branchstate@*/
00109         if (fp) {
00110             fdPush(u->ctrl, fpio, fp, -1);   /* Push fpio onto stack */
00111             (void) Fclose(u->ctrl);
00112         } else if (fdio->_fileno(u->ctrl) >= 0)
00113             xx = fdio->close(u->ctrl);
00114         /*@=branchstate@*/
00115 #else
00116         (void) Fclose(u->ctrl);
00117 #endif
00118 
00119         u->ctrl = fdio->_fdderef(u->ctrl, "persist ctrl (urlFree)", file, line);
00120         /*@-usereleased@*/
00121         if (u->ctrl)
00122             fprintf(stderr, _("warning: u %p ctrl %p nrefs != 0 (%s %s)\n"),
00123                         u, u->ctrl, (u->host ? u->host : ""),
00124                         (u->service ? u->service : ""));
00125         /*@=usereleased@*/
00126     }
00127     if (u->data) {
00128 #ifndef NOTYET
00129         void * fp = fdGetFp(u->data);
00130         if (fp) {
00131             fdPush(u->data, fpio, fp, -1);   /* Push fpio onto stack */
00132             (void) Fclose(u->data);
00133         } else if (fdio->_fileno(u->data) >= 0)
00134             xx = fdio->close(u->data);
00135 #else
00136         (void) Fclose(u->ctrl);
00137 #endif
00138 
00139         u->data = fdio->_fdderef(u->data, "persist data (urlFree)", file, line);
00140         /*@-usereleased@*/
00141         if (u->data)
00142             fprintf(stderr, _("warning: u %p data %p nrefs != 0 (%s %s)\n"),
00143                         u, u->data, (u->host ? u->host : ""),
00144                         (u->service ? u->service : ""));
00145         /*@=usereleased@*/
00146     }
00147     u->buf = _free(u->buf);
00148     u->url = _free(u->url);
00149     u->service = _free((void *)u->service);
00150     u->user = _free((void *)u->user);
00151     u->password = _free((void *)u->password);
00152     u->host = _free((void *)u->host);
00153     u->portstr = _free((void *)u->portstr);
00154     u->proxyu = _free((void *)u->proxyu);
00155     u->proxyh = _free((void *)u->proxyh);
00156 
00157     /*@-refcounttrans@*/ u = _free(u); /*@-refcounttrans@*/
00158     return NULL;
00159 }
00160 
00161 /*@-boundswrite@*/
00162 void urlFreeCache(void)
00163 {
00164     if (_url_cache) {
00165         int i;
00166         for (i = 0; i < _url_count; i++) {
00167             if (_url_cache[i] == NULL) continue;
00168             _url_cache[i] = urlFree(_url_cache[i], "_url_cache");
00169             if (_url_cache[i])
00170                 fprintf(stderr,
00171                         _("warning: _url_cache[%d] %p nrefs(%d) != 1 (%s %s)\n"),
00172                         i, _url_cache[i], _url_cache[i]->nrefs,
00173                         (_url_cache[i]->host ? _url_cache[i]->host : ""),
00174                         (_url_cache[i]->service ? _url_cache[i]->service : ""));
00175         }
00176     }
00177     _url_cache = _free(_url_cache);
00178     _url_count = 0;
00179 }
00180 /*@=boundswrite@*/
00181 
00182 static int urlStrcmp(/*@null@*/ const char * str1, /*@null@*/ const char * str2)
00183         /*@*/
00184 {
00185     if (str1)
00186         if (str2)
00187             return strcmp(str1, str2);
00188     if (str1 != str2)
00189         return -1;
00190     return 0;
00191 }
00192 
00193 /*@-boundswrite@*/
00194 /*@-mods@*/
00195 static void urlFind(/*@null@*/ /*@in@*/ /*@out@*/ urlinfo * uret, int mustAsk)
00196         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00197         /*@modifies *uret, rpmGlobalMacroContext, fileSystem, internalState @*/
00198 {
00199     urlinfo u;
00200     int ucx;
00201     int i = 0;
00202 
00203     if (uret == NULL)
00204         return;
00205 
00206     u = *uret;
00207     URLSANE(u);
00208 
00209     ucx = -1;
00210     for (i = 0; i < _url_count; i++) {
00211         urlinfo ou = NULL;
00212         if (_url_cache == NULL || (ou = _url_cache[i]) == NULL) {
00213             if (ucx < 0)
00214                 ucx = i;
00215             continue;
00216         }
00217 
00218         /* Check for cache-miss condition. A cache miss is
00219          *    a) both items are not NULL and don't compare.
00220          *    b) either of the items is not NULL.
00221          */
00222         if (urlStrcmp(u->service, ou->service))
00223             continue;
00224         if (urlStrcmp(u->host, ou->host))
00225             continue;
00226         if (urlStrcmp(u->user, ou->user))
00227             continue;
00228         if (urlStrcmp(u->portstr, ou->portstr))
00229             continue;
00230         break;  /* Found item in cache */
00231     }
00232 
00233     if (i == _url_count) {
00234         if (ucx < 0) {
00235             ucx = _url_count++;
00236             _url_cache = xrealloc(_url_cache, sizeof(*_url_cache) * _url_count);
00237         }
00238         if (_url_cache)         /* XXX always true */
00239             _url_cache[ucx] = urlLink(u, "_url_cache (miss)");
00240         u = urlFree(u, "urlSplit (urlFind miss)");
00241     } else {
00242         ucx = i;
00243         u = urlFree(u, "urlSplit (urlFind hit)");
00244     }
00245 
00246     /* This URL is now cached. */
00247 
00248     if (_url_cache)             /* XXX always true */
00249         u = urlLink(_url_cache[ucx], "_url_cache");
00250     *uret = u;
00251     /*@-usereleased@*/
00252     u = urlFree(u, "_url_cache (urlFind)");
00253     /*@=usereleased@*/
00254 
00255     /* Zap proxy host and port in case they have been reset */
00256     u->proxyp = -1;
00257     u->proxyh = _free(u->proxyh);
00258 
00259     /* Perform one-time FTP initialization */
00260     if (u->urltype == URL_IS_FTP) {
00261 
00262         if (mustAsk || (u->user != NULL && u->password == NULL)) {
00263             const char * host = (u->host ? u->host : "");
00264             const char * user = (u->user ? u->user : "");
00265             char * prompt;
00266             prompt = alloca(strlen(host) + strlen(user) + 256);
00267             sprintf(prompt, _("Password for %s@%s: "), user, host);
00268             u->password = _free(u->password);
00269 /*@-dependenttrans -moduncon @*/
00270             u->password = /*@-unrecog@*/ getpass(prompt) /*@=unrecog@*/;
00271 /*@=dependenttrans =moduncon @*/
00272             if (u->password)
00273                 u->password = xstrdup(u->password);
00274         }
00275 
00276         if (u->proxyh == NULL) {
00277             const char *proxy = rpmExpand("%{_ftpproxy}", NULL);
00278             if (proxy && *proxy != '%') {
00279                 /*@observer@*/ const char * host = (u->host ? u->host : "");
00280                 const char *uu = (u->user ? u->user : "anonymous");
00281                 char *nu = xmalloc(strlen(uu) + sizeof("@") + strlen(host));
                (void) stpcpy( stpcpy( stpcpy(nu, uu), "@"), host);
                u->proxyu = nu;
                u->proxyh = xstrdup(proxy);
            }
            proxy = _free(proxy);
        }

        if (u->proxyp < 0) {
            const char *proxy = rpmExpand("%{_ftpport}", NULL);
00282             if (proxy && *proxy != '%') {
00283                 char *end;
00284                 int port = strtol(proxy, &end, 0);
00285                 if (!(end && *end == '\0')) {
00286                     fprintf(stderr, _("error: %sport must be a number\n"),
00287                         (u->service ? u->service : ""));
00288                     return;
00289                 }
00290                 u->proxyp = port;
00291             }
00292             proxy = _free(proxy);
00293         }
00294     }
00295 
00296     /* Perform one-time HTTP initialization */
00297     if (u->urltype == URL_IS_HTTP) {
00298 
00299         if (u->proxyh == NULL) {
00300             const char *proxy = rpmExpand("%{_httpproxy}", NULL);
00301             if (proxy && *proxy != '%')
00302                 u->proxyh = xstrdup(proxy);
00303             proxy = _free(proxy);
00304         }
00305 
00306         if (u->proxyp < 0) {
00307             const char *proxy = rpmExpand("%{_httpport}", NULL);
00308             if (proxy && *proxy != '%') {
00309                 char *end;
00310                 int port = strtol(proxy, &end, 0);
00311                 if (!(end && *end == '\0')) {
00312                     fprintf(stderr, _("error: %sport must be a number\n"),
00313                         (u->service ? u->service : ""));
00314                     return;
00315                 }
00316                 u->proxyp = port;
00317             }
00318             proxy = _free(proxy);
00319         }
00320 
00321     }
00322 
00323     return;
00324 }
00325 /*@=mods@*/
00326 /*@=boundswrite@*/
00327 
00330 /*@observer@*/ /*@unchecked@*/
00331 static struct urlstring {
00332 /*@observer@*/ /*@null@*/
00333     const char * leadin;
00334     urltype     ret;
00335 } urlstrings[] = {
00336     { "file://",        URL_IS_PATH },
00337     { "ftp://",         URL_IS_FTP },
00338     { "http://",        URL_IS_HTTP },
00339     { "-",              URL_IS_DASH },
00340     { NULL,             URL_IS_UNKNOWN }
00341 };
00342 
00343 urltype urlIsURL(const char * url)
00344 {
00345     struct urlstring *us;
00346 
00347 /*@-boundsread@*/
00348     if (url && *url) {
00349         for (us = urlstrings; us->leadin != NULL; us++) {
00350             if (strncmp(url, us->leadin, strlen(us->leadin)))
00351                 continue;
00352             return us->ret;
00353         }
00354     }
00355 /*@=boundsread@*/
00356 
00357     return URL_IS_UNKNOWN;
00358 }
00359 
00360 /*@-boundswrite@*/
00361 /* Return path portion of url (or pointer to NUL if url == NULL) */
00362 urltype urlPath(const char * url, const char ** pathp)
00363 {
00364     const char *path;
00365     int urltype;
00366 
00367     path = url;
00368     urltype = urlIsURL(url);
00369     /*@-branchstate@*/
00370     switch (urltype) {
00371     case URL_IS_FTP:
00372         url += sizeof("ftp://") - 1;
00373         path = strchr(url, '/');
00374         if (path == NULL) path = url + strlen(url);
00375         break;
00376     case URL_IS_HTTP:
00377     case URL_IS_PATH:
00378         url += sizeof("file://") - 1;
00379         path = strchr(url, '/');
00380         if (path == NULL) path = url + strlen(url);
00381         break;
00382     case URL_IS_UNKNOWN:
00383         if (path == NULL) path = "";
00384         break;
00385     case URL_IS_DASH:
00386         path = "";
00387         break;
00388     }
00389     /*@=branchstate@*/
00390     if (pathp)
00391         /*@-observertrans@*/
00392         *pathp = path;
00393         /*@=observertrans@*/
00394     return urltype;
00395 }
00396 /*@=boundswrite@*/
00397 
00398 /*
00399  * Split URL into components. The URL can look like
00400  *      service://user:password@host:port/path
00401  */
00402 /*@-bounds@*/
00403 /*@-modfilesys@*/
00404 int urlSplit(const char * url, urlinfo *uret)
00405 {
00406     urlinfo u;
00407     char *myurl;
00408     char *s, *se, *f, *fe;
00409 
00410     if (uret == NULL)
00411         return -1;
00412     if ((u = urlNew("urlSplit")) == NULL)
00413         return -1;
00414 
00415     if ((se = s = myurl = xstrdup(url)) == NULL) {
00416         u = urlFree(u, "urlSplit (error #1)");
00417         return -1;
00418     }
00419 
00420     u->url = xstrdup(url);
00421     u->urltype = urlIsURL(url);
00422 
00423     while (1) {
00424         /* Point to end of next item */
00425         while (*se && *se != '/') se++;
00426         /* Item was service. Save service and go for the rest ...*/
00427         if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
00428                 se[-1] = '\0';
00429             u->service = xstrdup(s);
00430             se += 2;    /* skip over "//" */
00431             s = se++;
00432             continue;
00433         }
00434         
00435         /* Item was everything-but-path. Continue parse on rest */
00436         *se = '\0';
00437         break;
00438     }
00439 
00440     /* Look for ...@host... */
00441     fe = f = s;
00442     while (*fe && *fe != '@') fe++;
00443     /*@-branchstate@*/
00444     if (*fe == '@') {
00445         s = fe + 1;
00446         *fe = '\0';
00447         /* Look for user:password@host... */
00448         while (fe > f && *fe != ':') fe--;
00449         if (*fe == ':') {
00450             *fe++ = '\0';
00451             u->password = xstrdup(fe);
00452         }
00453         u->user = xstrdup(f);
00454     }
00455     /*@=branchstate@*/
00456 
00457     /* Look for ...host:port */
00458     fe = f = s;
00459     while (*fe && *fe != ':') fe++;
00460     if (*fe == ':') {
00461         *fe++ = '\0';
00462         u->portstr = xstrdup(fe);
00463         if (u->portstr != NULL && u->portstr[0] != '\0') {
00464             char *end;
00465             u->port = strtol(u->portstr, &end, 0);
00466             if (!(end && *end == '\0')) {
00467                 rpmMessage(RPMMESS_ERROR, _("url port must be a number\n"));
00468                 myurl = _free(myurl);
00469                 u = urlFree(u, "urlSplit (error #3)");
00470                 return -1;
00471             }
00472         }
00473     }
00474     u->host = xstrdup(f);
00475 
00476     if (u->port < 0 && u->service != NULL) {
00477         struct servent *serv;
00478         /*@-multithreaded -moduncon @*/
00479         serv = getservbyname(u->service, "tcp");
00480         /*@=multithreaded =moduncon @*/
00481         if (serv != NULL)
00482             u->port = ntohs(serv->s_port);
00483         else if (u->urltype == URL_IS_FTP)
00484             u->port = IPPORT_FTP;
00485         else if (u->urltype == URL_IS_HTTP)
00486             u->port = IPPORT_HTTP;
00487     }
00488 
00489     myurl = _free(myurl);
00490     if (uret) {
00491         *uret = u;
00492 /*@-globs -mods @*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
00493         urlFind(uret, 0);
00494 /*@=globs =mods @*/
00495     }
00496     return 0;
00497 }
00498 /*@=modfilesys@*/
00499 /*@=bounds@*/
00500 
00501 int urlGetFile(const char * url, const char * dest)
00502 {
00503     int rc;
00504     FD_t sfd = NULL;
00505     FD_t tfd = NULL;
00506     const char * sfuPath = NULL;
00507     int urlType = urlPath(url, &sfuPath);
00508 
00509     if (*sfuPath == '\0')
00510         return FTPERR_UNKNOWN;
00511         
00512     sfd = Fopen(url, "r.ufdio");
00513     if (sfd == NULL || Ferror(sfd)) {
00514         rpmMessage(RPMMESS_DEBUG, _("failed to open %s: %s\n"), url, Fstrerror(sfd));
00515         rc = FTPERR_UNKNOWN;
00516         goto exit;
00517     }
00518 
00519     if (dest == NULL) {
00520         if ((dest = strrchr(sfuPath, '/')) != NULL)
00521             dest++;
00522         else
00523             dest = sfuPath;
00524     }
00525 
00526     if (dest == NULL)
00527         return FTPERR_UNKNOWN;
00528 
00529     tfd = Fopen(dest, "w.ufdio");
00530 if (_url_debug)
00531 fprintf(stderr, "*** urlGetFile sfd %p %s tfd %p %s\n", sfd, url, (tfd ? tfd : NULL), dest);
00532     if (tfd == NULL || Ferror(tfd)) {
00533         /* XXX Fstrerror */
00534         rpmMessage(RPMMESS_DEBUG, _("failed to create %s: %s\n"), dest, Fstrerror(tfd));
00535         rc = FTPERR_UNKNOWN;
00536         goto exit;
00537     }
00538 
00539     switch (urlType) {
00540     case URL_IS_FTP:
00541     case URL_IS_HTTP:
00542     case URL_IS_PATH:
00543     case URL_IS_DASH:
00544     case URL_IS_UNKNOWN:
00545         if ((rc = ufdGetFile(sfd, tfd))) {
00546             (void) Unlink(dest);
00547             /* XXX FIXME: sfd possibly closed by copyData */
00548             /*@-usereleased@*/ (void) Fclose(sfd) /*@=usereleased@*/ ;
00549         }
00550         sfd = NULL;     /* XXX Fclose(sfd) done by ufdGetFile */
00551         break;
00552     default:
00553         rc = FTPERR_UNKNOWN;
00554         break;
00555     }
00556 
00557 exit:
00558     if (tfd)
00559         (void) Fclose(tfd);
00560     if (sfd)
00561         (void) Fclose(sfd);
00562 
00563     return rc;
00564 }
00565 

Generated on Fri Apr 16 16:36:54 2004 for rpm by doxygen 1.3.6