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