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

Generated on Wed Mar 13 15:34:51 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002