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

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

Generated on Tue Sep 7 21:40:42 2010 for rpm by  doxygen 1.3.9.1