00001
00005 #include "system.h"
00006
00007 #include <netinet/in.h>
00008
00009 #include <rpmmacro.h>
00010 #include <rpmcb.h>
00011 #include <rpmio_internal.h>
00012 #ifdef WITH_NEON
00013 #include <rpmdav.h>
00014 #endif
00015
00016 #include "debug.h"
00017
00018
00019
00020
00021 #ifndef IPPORT_FTP
00022 #define IPPORT_FTP 21
00023 #endif
00024 #ifndef IPPORT_HTTP
00025 #define IPPORT_HTTP 80
00026 #endif
00027 #ifndef IPPORT_HTTPS
00028 #define IPPORT_HTTPS 443
00029 #endif
00030 #ifndef IPPORT_PGPKEYSERVER
00031 #define IPPORT_PGPKEYSERVER 11371
00032 #endif
00033
00036
00037 int (*urlNotify) (const urlinfo u, unsigned status)
00038 ;
00039
00040
00043
00044 void * urlNotifyArg;
00045
00048
00049 int _url_iobuf_size = RPMURL_IOBUF_SIZE;
00050
00053
00054 int _url_debug = 0;
00055
00056 #define URLDBG(_f, _m, _x) if ((_url_debug | (_f)) & (_m)) fprintf _x
00057
00058 #define URLDBGIO(_f, _x) URLDBG((_f), RPMURL_DEBUG_IO, _x)
00059 #define URLDBGREFS(_f, _x) URLDBG((_f), RPMURL_DEBUG_REFS, _x)
00060
00063
00064
00065 urlinfo *_url_cache = NULL;
00066
00067 static void urlFini(void * _u)
00068
00069
00070 {
00071 urlinfo u =_u;
00072 int xx;
00073
00074 if (u->ctrl) {
00075 #ifndef NOTYET
00076 void * fp = fdGetFp(u->ctrl);
00077 if (fp) {
00078 fdPush(u->ctrl, fpio, fp, -1);
00079 xx = Fclose(u->ctrl);
00080 } else if (fdFileno(u->ctrl) >= 0)
00081 xx = fdio->close(u->ctrl);
00082 #else
00083 xx = Fclose(u->ctrl);
00084 #endif
00085
00086
00087 u->ctrl = (FD_t)rpmioFreePoolItem((rpmioItem)u->ctrl, "persist ctrl (urlFree)", __FILE__, __LINE__);
00088 if (u->ctrl)
00089 fprintf(stderr, _("warning: u %p ctrl %p nrefs != 0 (%s %s)\n"),
00090 u, u->ctrl, (u->host ? u->host : ""),
00091 (u->scheme ? u->scheme : ""));
00092
00093 }
00094 if (u->data) {
00095 #ifndef NOTYET
00096 void * fp = fdGetFp(u->data);
00097 if (fp) {
00098 fdPush(u->data, fpio, fp, -1);
00099 xx = Fclose(u->data);
00100 } else if (fdFileno(u->data) >= 0)
00101 xx = fdio->close(u->data);
00102 #else
00103 xx = Fclose(u->ctrl);
00104 #endif
00105
00106
00107 u->data = (FD_t)rpmioFreePoolItem((rpmioItem)u->data, "persist data (urlFree)", __FILE__, __LINE__);
00108 if (u->data)
00109 fprintf(stderr, _("warning: u %p data %p nrefs != 0 (%s %s)\n"),
00110 u, u->data, (u->host ? u->host : ""),
00111 (u->scheme ? u->scheme : ""));
00112
00113 }
00114 #ifdef WITH_NEON
00115 xx = davFree(u);
00116 #endif
00117 u->etag = _free(u->etag);
00118 u->location = _free(u->location);
00119 u->rop = _free(u->rop);
00120 u->sop = _free(u->sop);
00121 u->top = _free(u->top);
00122 u->buf = _free(u->buf);
00123 u->url = _free(u->url);
00124 u->scheme = _free((void *)u->scheme);
00125 u->user = _free((void *)u->user);
00126 u->password = _free((void *)u->password);
00127 u->host = _free((void *)u->host);
00128 u->portstr = _free((void *)u->portstr);
00129 u->query = _free(u->query);
00130 u->fragment = _free(u->fragment);
00131 u->proxyu = _free((void *)u->proxyu);
00132 u->proxyh = _free((void *)u->proxyh);
00133 }
00134
00137
00138 int _url_count = 0;
00139
00140
00141 rpmioPool _urlPool;
00142
00143 static urlinfo urlGetPool( rpmioPool pool)
00144
00145
00146 {
00147 urlinfo u;
00148
00149 if (_urlPool == NULL) {
00150 _urlPool = rpmioNewPool("u", sizeof(*u), -1, _url_debug,
00151 NULL, NULL, urlFini);
00152 pool = _urlPool;
00153 }
00154 return (urlinfo) rpmioGetPool(pool, sizeof(*u));
00155 }
00156
00157 urlinfo XurlNew(const char *msg, const char *fn, unsigned ln)
00158 {
00159 urlinfo u = urlGetPool(_urlPool);
00160
00161 u->proxyp = -1;
00162 u->port = -1;
00163 u->urltype = URL_IS_UNKNOWN;
00164 u->ctrl = NULL;
00165 u->data = NULL;
00166 u->location = NULL;
00167 u->etag = NULL;
00168 u->notify = urlNotify;
00169
00170 u->arg = urlNotifyArg;
00171
00172 u->rop = xcalloc(1, sizeof(*u->rop));
00173 u->sop = xcalloc(1, sizeof(*u->sop));
00174 u->top = xcalloc(1, sizeof(*u->top));
00175 u->bufAlloced = 0;
00176 u->buf = NULL;
00177 u->allow = RPMURL_SERVER_HASRANGE;
00178 u->httpVersion = 0;
00179 u->magic = URLMAGIC;
00180 return (urlinfo) rpmioLinkPoolItem((rpmioItem)u, msg, fn, ln);
00181 }
00182
00183 void urlFreeCache(void)
00184 {
00185 if (_url_cache) {
00186 int i;
00187 for (i = 0; i < _url_count; i++) {
00188 if (_url_cache[i] == NULL) continue;
00189 _url_cache[i] = urlFree(_url_cache[i], "_url_cache");
00190 if (_url_cache[i] == NULL)
00191 continue;
00192 yarnPossess(_url_cache[i]->_item.use);
00193 fprintf(stderr,
00194 _("warning: _url_cache[%d] %p nrefs(%ld) != 1 (%s %s)\n"),
00195 i, _url_cache[i], yarnPeekLock(_url_cache[i]->_item.use),
00196 (_url_cache[i]->host ? _url_cache[i]->host : ""),
00197 (_url_cache[i]->scheme ? _url_cache[i]->scheme : ""));
00198 yarnRelease(_url_cache[i]->_item.use);
00199 }
00200 }
00201 _url_cache = _free(_url_cache);
00202 _url_count = 0;
00203 }
00204
00205 static int urlStrcmp( const char * str1, const char * str2)
00206
00207 {
00208 if (str1)
00209 if (str2)
00210 return strcmp(str1, str2);
00211 if (str1 != str2)
00212 return -1;
00213 return 0;
00214 }
00215
00216
00217 static void urlFind( urlinfo * uret, int mustAsk)
00218
00219
00220 {
00221 urlinfo u;
00222 int ucx;
00223 int i = 0;
00224
00225 if (uret == NULL)
00226 return;
00227
00228 u = *uret;
00229 URLSANE(u);
00230
00231 ucx = -1;
00232 for (i = 0; i < _url_count; i++) {
00233 urlinfo ou = NULL;
00234 if (_url_cache == NULL || (ou = _url_cache[i]) == NULL) {
00235 if (ucx < 0)
00236 ucx = i;
00237 continue;
00238 }
00239
00240
00241
00242
00243
00244 if (urlStrcmp(u->scheme, ou->scheme))
00245 continue;
00246 if (urlStrcmp(u->host, ou->host))
00247 continue;
00248 if (urlStrcmp(u->user, ou->user))
00249 continue;
00250 if (urlStrcmp(u->portstr, ou->portstr))
00251 continue;
00252 break;
00253 }
00254
00255 if (i == _url_count) {
00256 if (ucx < 0) {
00257 ucx = _url_count++;
00258 _url_cache = xrealloc(_url_cache, sizeof(*_url_cache) * _url_count);
00259 }
00260 if (_url_cache)
00261 _url_cache[ucx] = urlLink(u, "_url_cache (miss)");
00262 u = urlFree(u, "urlSplit (urlFind miss)");
00263 } else {
00264 ucx = i;
00265 u = urlFree(u, "urlSplit (urlFind hit)");
00266 }
00267
00268
00269
00270 if (_url_cache)
00271 u = urlLink(_url_cache[ucx], "_url_cache");
00272 *uret = u;
00273
00274 u = urlFree(u, "_url_cache (urlFind)");
00275
00276 assert(u != NULL);
00277
00278
00279 u->proxyp = -1;
00280 u->proxyh = _free(u->proxyh);
00281
00282
00283 if (u->urltype == URL_IS_FTP) {
00284
00285 if (mustAsk || (u->user != NULL && u->password == NULL)) {
00286 const char * host = (u->host ? u->host : "");
00287 const char * user = (u->user ? u->user : "");
00288 char * prompt;
00289 prompt = alloca(strlen(host) + strlen(user) + 256);
00290 sprintf(prompt, _("Password for %s@%s: "), user, host);
00291 u->password = _free(u->password);
00292
00293 u->password = Getpass(prompt);
00294
00295 if (u->password)
00296 u->password = xstrdup(u->password);
00297 }
00298
00299 if (u->proxyh == NULL) {
00300 const char *proxy = rpmExpand("%{_ftpproxy}", NULL);
00301 if (proxy && *proxy != '%') {
00302
00303 const char * host = (u->host ? u->host : "");
00304 const char *uu = (u->user ? u->user : "anonymous");
00305 char *nu = xmalloc(strlen(uu) + sizeof("@") + strlen(host));
00306 (void) stpcpy( stpcpy( stpcpy(nu, uu), "@"), host);
00307 u->proxyu = nu;
00308 u->proxyh = xstrdup(proxy);
00309 }
00310 proxy = _free(proxy);
00311 }
00312
00313 if (u->proxyp < 0) {
00314 const char *proxy = rpmExpand("%{_ftpport}", NULL);
00315 if (proxy && *proxy != '%') {
00316 char *end = NULL;
00317 int port = strtol(proxy, &end, 0);
00318 if (!(end && *end == '\0')) {
00319 fprintf(stderr, _("error: %sport must be a number\n"),
00320 (u->scheme ? u->scheme : ""));
00321 return;
00322 }
00323 u->proxyp = port;
00324 }
00325 proxy = _free(proxy);
00326 }
00327 }
00328
00329
00330 if (u->urltype == URL_IS_HTTP || u->urltype == URL_IS_HTTPS || u->urltype == URL_IS_HKP) {
00331
00332 if (u->proxyh == NULL) {
00333 const char *proxy = rpmExpand("%{_httpproxy}", NULL);
00334 if (proxy && *proxy != '%')
00335 u->proxyh = xstrdup(proxy);
00336 proxy = _free(proxy);
00337 }
00338
00339 if (u->proxyp < 0) {
00340 const char *proxy = rpmExpand("%{_httpport}", NULL);
00341 if (proxy && *proxy != '%') {
00342 char *end;
00343 int port = strtol(proxy, &end, 0);
00344 if (!(end && *end == '\0')) {
00345 fprintf(stderr, _("error: %sport must be a number\n"),
00346 (u->scheme ? u->scheme : ""));
00347 return;
00348 }
00349 u->proxyp = port;
00350 }
00351 proxy = _free(proxy);
00352 }
00353
00354 }
00355
00356 return;
00357 }
00358
00359
00362
00363 static struct urlstring {
00364
00365 const char * leadin;
00366 urltype ret;
00367 } urlstrings[] = {
00368 { "file://", URL_IS_PATH },
00369 { "ftp://", URL_IS_FTP },
00370 { "hkp://", URL_IS_HKP },
00371 { "http://", URL_IS_HTTP },
00372 { "https://", URL_IS_HTTPS },
00373 { "-", URL_IS_DASH },
00374 { NULL, URL_IS_UNKNOWN }
00375 };
00376
00377 urltype urlIsURL(const char * url)
00378 {
00379 struct urlstring *us;
00380
00381 if (url && *url) {
00382 for (us = urlstrings; us->leadin != NULL; us++) {
00383 if (strncmp(url, us->leadin, strlen(us->leadin)))
00384 continue;
00385 return us->ret;
00386 }
00387 }
00388
00389 return URL_IS_UNKNOWN;
00390 }
00391
00392
00393 urltype urlPath(const char * url, const char ** pathp)
00394 {
00395 const char *path;
00396 int urltype;
00397
00398 path = url;
00399 urltype = urlIsURL(url);
00400 switch (urltype) {
00401 case URL_IS_FTP:
00402 url += sizeof("ftp://") - 1;
00403 path = strchr(url, '/');
00404 if (path == NULL) path = url + strlen(url);
00405 break;
00406 case URL_IS_PATH:
00407 url += sizeof("file://") - 1;
00408 path = strchr(url, '/');
00409 if (path == NULL) path = url + strlen(url);
00410 break;
00411 case URL_IS_HKP:
00412 url += sizeof("hkp://") - 1;
00413 path = strchr(url, '/');
00414 if (path == NULL) path = url + strlen(url);
00415 break;
00416 case URL_IS_HTTP:
00417 url += sizeof("http://") - 1;
00418 path = strchr(url, '/');
00419 if (path == NULL) path = url + strlen(url);
00420 break;
00421 case URL_IS_HTTPS:
00422 url += sizeof("https://") - 1;
00423 path = strchr(url, '/');
00424 if (path == NULL) path = url + strlen(url);
00425 break;
00426 case URL_IS_UNKNOWN:
00427 if (path == NULL) path = "";
00428 break;
00429 case URL_IS_DASH:
00430 path = "";
00431 break;
00432 }
00433 if (pathp)
00434
00435 *pathp = path;
00436
00437 return urltype;
00438 }
00439
00443 static const char * urlStrdup(const char * url)
00444
00445 {
00446 size_t nb = strlen(url);
00447 char * t = xmalloc(nb + 1 + 1);
00448 const char * nurl = t;
00449 while (*url != '\0')
00450 *t++ = *url++;
00451 *t = '\0';
00452 return nurl;
00453 }
00454
00455
00456
00457
00458
00459
00460
00461
00462 int urlSplit(const char * url, urlinfo *uret)
00463 {
00464 urlinfo u;
00465 char *myurl;
00466 char *s, *se, *f, *fe;
00467
00468 if (uret == NULL)
00469 return -1;
00470 if ((u = urlNew("urlSplit")) == NULL)
00471 return -1;
00472
00473 myurl = xstrdup(url);
00474 if ((se = strrchr(myurl, '#')) != NULL) {
00475 *se++ = '\0';
00476 u->fragment = xstrdup(se);
00477 }
00478 if ((se = strrchr(myurl, '?')) != NULL) {
00479 *se++ = '\0';
00480 u->query = xstrdup(se);
00481 }
00482
00483 u->url = urlStrdup(myurl);
00484 u->urltype = urlIsURL(myurl);
00485
00486 se = s = myurl;
00487 while (1) {
00488
00489 while (*se && *se != '/') se++;
00490
00491 if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
00492 se[-1] = '\0';
00493 u->scheme = xstrdup(s);
00494 se += 2;
00495 s = se++;
00496 continue;
00497 }
00498
00499
00500 *se = '\0';
00501 break;
00502 }
00503
00504
00505 fe = f = s;
00506 while (*fe && *fe != '@') fe++;
00507 if (*fe == '@') {
00508 s = fe + 1;
00509 *fe = '\0';
00510
00511 while (fe > f && *fe != ':') fe--;
00512 if (*fe == ':') {
00513 *fe++ = '\0';
00514 u->password = xstrdup(fe);
00515 }
00516 u->user = xstrdup(f);
00517 }
00518
00519
00520 fe = f = s;
00521 if (strchr(fe, '[') && strchr(fe, ']')) {
00522 fe = strchr(f, ']');
00523 *f++ = '\0';
00524 *fe++ = '\0';
00525 }
00526 assert(fe != NULL);
00527 while (*fe && *fe != ':') fe++;
00528 if (*fe == ':') {
00529 *fe++ = '\0';
00530 u->portstr = xstrdup(fe);
00531 if (u->portstr != NULL && u->portstr[0] != '\0') {
00532 char *end;
00533 u->port = strtol(u->portstr, &end, 0);
00534 if (!(end && *end == '\0')) {
00535 rpmlog(RPMLOG_ERR, _("url port must be a number\n"));
00536 myurl = _free(myurl);
00537 u = urlFree(u, "urlSplit (error #3)");
00538 return -1;
00539 }
00540 }
00541 }
00542 u->host = xstrdup(f);
00543
00544 if (u->port < 0 && u->scheme != NULL) {
00545 struct servent *serv;
00546
00547
00548 serv = getservbyname(u->scheme, "tcp");
00549
00550 if (serv != NULL)
00551 u->port = (int) ntohs(serv->s_port);
00552 else if (u->urltype == URL_IS_FTP)
00553 u->port = IPPORT_FTP;
00554 else if (u->urltype == URL_IS_HKP)
00555 u->port = IPPORT_PGPKEYSERVER;
00556 else if (u->urltype == URL_IS_HTTP)
00557 u->port = IPPORT_HTTP;
00558 else if (u->urltype == URL_IS_HTTPS)
00559 u->port = IPPORT_HTTPS;
00560 }
00561
00562 myurl = _free(myurl);
00563 if (uret) {
00564 *uret = u;
00565
00566 urlFind(uret, 0);
00567
00568 }
00569 return 0;
00570 }
00571
00572
00573 int urlGetFile(const char * url, const char * dest)
00574 {
00575 int rc;
00576 FD_t sfd = NULL;
00577 FD_t tfd = NULL;
00578 const char * sfuPath = NULL;
00579 int urlType = urlPath(url, &sfuPath);
00580 char *result;
00581
00582 if (*sfuPath == '\0')
00583 return FTPERR_UNKNOWN;
00584
00585 if (dest == NULL) {
00586 if ((dest = strrchr(sfuPath, '/')) != NULL)
00587 dest++;
00588 else
00589 dest = sfuPath;
00590 }
00591 if (dest == NULL)
00592 return FTPERR_UNKNOWN;
00593
00594
00595 if (rpmExpandNumeric("%{?__urlgetfile:1}%{!?__urlgetfile:0}")) {
00596 result = rpmExpand("%{__urlgetfile ", url, " ", dest, "}", NULL);
00597 if (result != NULL && strcmp(result, "OK") == 0)
00598 rc = 0;
00599 else {
00600 rpmlog(RPMLOG_DEBUG, D_("failed to fetch URL %s via external command\n"), url);
00601 rc = FTPERR_UNKNOWN;
00602 }
00603 result = _free(result);
00604 goto exit;
00605 }
00606
00607
00608 sfd = Fopen(url, "r.ufdio");
00609 if (sfd == NULL || Ferror(sfd)) {
00610 rpmlog(RPMLOG_DEBUG, D_("failed to open %s: %s\n"), url, Fstrerror(sfd));
00611 rc = FTPERR_UNKNOWN;
00612 goto exit;
00613 }
00614
00615
00616 tfd = Fopen(dest, "w");
00617 if (_url_debug)
00618 fprintf(stderr, "*** urlGetFile sfd %p %s tfd %p %s\n", sfd, url, (tfd ? tfd : NULL), dest);
00619 if (tfd == NULL || Ferror(tfd)) {
00620 rpmlog(RPMLOG_DEBUG, D_("failed to create %s: %s\n"), dest, Fstrerror(tfd));
00621 rc = FTPERR_UNKNOWN;
00622 goto exit;
00623 }
00624
00625 switch (urlType) {
00626 case URL_IS_HTTPS:
00627 case URL_IS_HTTP:
00628 case URL_IS_HKP:
00629 case URL_IS_FTP:
00630 case URL_IS_PATH:
00631 case URL_IS_DASH:
00632 case URL_IS_UNKNOWN:
00633 if ((rc = ufdGetFile(sfd, tfd))) {
00634 (void) Unlink(dest);
00635
00636 (void) Fclose(sfd) ;
00637 }
00638 sfd = NULL;
00639 break;
00640 default:
00641 rc = FTPERR_UNKNOWN;
00642 break;
00643 }
00644
00645 exit:
00646 if (tfd)
00647 (void) Fclose(tfd);
00648 if (sfd)
00649 (void) Fclose(sfd);
00650
00651 return rc;
00652 }