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