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