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