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