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