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