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
00057 urlinfo XurlLink(urlinfo u, const char *msg, const char *file, unsigned line)
00058 {
00059 URLSANE(u);
00060 u->nrefs++;
00061
00062 URLDBGREFS(0, (stderr, "--> url %p ++ %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
00063
00064 return u;
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 return u;
00095 if (u->ctrl) {
00096 #ifndef NOTYET
00097 void * fp = fdGetFp(u->ctrl);
00098
00099 if (fp) {
00100 fdPush(u->ctrl, fpio, fp, -1);
00101 (void) Fclose(u->ctrl);
00102 } else if (fdFileno(u->ctrl) >= 0)
00103 xx = fdio->close(u->ctrl);
00104
00105 #else
00106 xx = Fclose(u->ctrl);
00107 #endif
00108
00109 u->ctrl = XfdFree(u->ctrl, "persist ctrl (urlFree)", file, line);
00110
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
00116 }
00117 if (u->data) {
00118 #ifndef NOTYET
00119 void * fp = fdGetFp(u->data);
00120 if (fp) {
00121 fdPush(u->data, fpio, fp, -1);
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
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
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 u = _free(u);
00148 return NULL;
00149 }
00150
00151
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
00171
00172 static int urlStrcmp( const char * str1, 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
00184
00185 static void urlFind( urlinfo * uret, int mustAsk)
00186
00187
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
00209
00210
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;
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)
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
00237
00238 if (_url_cache)
00239 u = urlLink(_url_cache[ucx], "_url_cache");
00240 *uret = u;
00241
00242 u = urlFree(u, "_url_cache (urlFind)");
00243
00244
00245
00246 u->proxyp = -1;
00247 u->proxyh = _free(u->proxyh);
00248
00249
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
00260 u->password = Getpass(prompt);
00261
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
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
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
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
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
00358
00359 return URL_IS_UNKNOWN;
00360 }
00361
00362
00363
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
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
00406 if (pathp)
00407
00408 *pathp = path;
00409
00410 return urltype;
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
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
00443 while (*se && *se != '/') se++;
00444
00445 if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
00446 se[-1] = '\0';
00447 u->scheme = xstrdup(s);
00448 se += 2;
00449 s = se++;
00450 continue;
00451 }
00452
00453
00454 *se = '\0';
00455 break;
00456 }
00457
00458
00459 fe = f = s;
00460 while (*fe && *fe != '@') fe++;
00461
00462 if (*fe == '@') {
00463 s = fe + 1;
00464 *fe = '\0';
00465
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
00474
00475
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
00503
00504 serv = getservbyname(u->scheme, "tcp");
00505
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
00522 urlFind(uret, 0);
00523
00524 }
00525 return 0;
00526 }
00527
00528
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
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
00579 (void) Fclose(sfd) ;
00580 }
00581 sfd = NULL;
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 }