Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

rpmio/url.c

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

Generated at Mon May 21 08:53:41 2001 for rpm by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001