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

Generated on Mon Aug 23 12:43:43 2010 for rpm by  doxygen 1.4.4