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

rpmio/url.c

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

Generated on Sun Oct 17 02:13:04 2004 for rpm by doxygen 1.3.6