7 #include <netinet/in.h>
10 #include <rpmmessages.h>
11 #include <rpmio_internal.h>
15 /*@access FD_t@*/ /* XXX compared with NULL */
22 #define IPPORT_HTTP 80
28 int _url_iobuf_size = RPMURL_IOBUF_SIZE;
35 #define URLDBG(_f, _m, _x) if ((_url_debug | (_f)) & (_m)) fprintf _x
37 #define URLDBGIO(_f, _x) URLDBG((_f), RPMURL_DEBUG_IO, _x)
38 #define URLDBGREFS(_f, _x) URLDBG((_f), RPMURL_DEBUG_REFS, _x)
45 urlinfo *_url_cache = NULL;
56 * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
57 * @param p memory to free
60 /*@unused@*/ static inline /*@null@*/ void *
61 _free(/*@only@*/ /*@null@*/ const void * p) /*@modifies p@*/
63 if (p != NULL) free((void *)p);
67 urlinfo XurlLink(urlinfo u, const char *msg, const char *file, unsigned line)
72 URLDBGREFS(0, (stderr, "--> url %p ++ %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
74 /*@-refcounttrans@*/ return u; /*@=refcounttrans@*/
77 urlinfo XurlNew(const char *msg, const char *file, unsigned line)
80 if ((u = xmalloc(sizeof(*u))) == NULL)
82 memset(u, 0, sizeof(*u));
85 u->urltype = URL_IS_UNKNOWN;
94 return XurlLink(u, msg, file, line);
97 urlinfo XurlFree(urlinfo u, const char *msg, const char *file, unsigned line)
102 URLDBGREFS(0, (stderr, "--> url %p -- %d %s at %s:%u\n", u, u->nrefs, msg, file, line));
104 /*@-refcounttrans -retalias@*/ return u; /*@=refcounttrans =retalias@*/
107 void * fp = fdGetFp(u->ctrl);
110 fdPush(u->ctrl, fpio, fp, -1); /* Push fpio onto stack */
111 (void) Fclose(u->ctrl);
112 } else if (fdio->_fileno(u->ctrl) >= 0)
113 xx = fdio->close(u->ctrl);
116 (void) Fclose(u->ctrl);
119 u->ctrl = fdio->_fdderef(u->ctrl, "persist ctrl (urlFree)", file, line);
122 fprintf(stderr, _("warning: u %p ctrl %p nrefs != 0 (%s %s)\n"),
123 u, u->ctrl, (u->host ? u->host : ""),
124 (u->service ? u->service : ""));
129 void * fp = fdGetFp(u->data);
131 fdPush(u->data, fpio, fp, -1); /* Push fpio onto stack */
132 (void) Fclose(u->data);
133 } else if (fdio->_fileno(u->data) >= 0)
134 xx = fdio->close(u->data);
136 (void) Fclose(u->ctrl);
139 u->data = fdio->_fdderef(u->data, "persist data (urlFree)", file, line);
142 fprintf(stderr, _("warning: u %p data %p nrefs != 0 (%s %s)\n"),
143 u, u->data, (u->host ? u->host : ""),
144 (u->service ? u->service : ""));
147 u->buf = _free(u->buf);
148 u->url = _free(u->url);
149 u->service = _free((void *)u->service);
150 u->user = _free((void *)u->user);
151 u->password = _free((void *)u->password);
152 u->host = _free((void *)u->host);
153 u->portstr = _free((void *)u->portstr);
154 u->proxyu = _free((void *)u->proxyu);
155 u->proxyh = _free((void *)u->proxyh);
157 /*@-refcounttrans@*/ u = _free(u); /*@-refcounttrans@*/
162 void urlFreeCache(void)
166 for (i = 0; i < _url_count; i++) {
167 if (_url_cache[i] == NULL) continue;
168 _url_cache[i] = urlFree(_url_cache[i], "_url_cache");
171 _("warning: _url_cache[%d] %p nrefs(%d) != 1 (%s %s)\n"),
172 i, _url_cache[i], _url_cache[i]->nrefs,
173 (_url_cache[i]->host ? _url_cache[i]->host : ""),
174 (_url_cache[i]->service ? _url_cache[i]->service : ""));
177 _url_cache = _free(_url_cache);
182 static int urlStrcmp(/*@null@*/ const char * str1, /*@null@*/ const char * str2)
187 return strcmp(str1, str2);
195 static void urlFind(/*@null@*/ /*@in@*/ /*@out@*/ urlinfo * uret, int mustAsk)
196 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
197 /*@modifies *uret, rpmGlobalMacroContext, fileSystem, internalState @*/
210 for (i = 0; i < _url_count; i++) {
212 if (_url_cache == NULL || (ou = _url_cache[i]) == NULL) {
218 /* Check for cache-miss condition. A cache miss is
219 * a) both items are not NULL and don't compare.
220 * b) either of the items is not NULL.
222 if (urlStrcmp(u->service, ou->service))
224 if (urlStrcmp(u->host, ou->host))
226 if (urlStrcmp(u->user, ou->user))
228 if (urlStrcmp(u->portstr, ou->portstr))
230 break; /* Found item in cache */
233 if (i == _url_count) {
236 _url_cache = xrealloc(_url_cache, sizeof(*_url_cache) * _url_count);
238 if (_url_cache) /* XXX always true */
239 _url_cache[ucx] = urlLink(u, "_url_cache (miss)");
240 u = urlFree(u, "urlSplit (urlFind miss)");
243 u = urlFree(u, "urlSplit (urlFind hit)");
246 /* This URL is now cached. */
248 if (_url_cache) /* XXX always true */
249 u = urlLink(_url_cache[ucx], "_url_cache");
252 u = urlFree(u, "_url_cache (urlFind)");
255 /* Zap proxy host and port in case they have been reset */
257 u->proxyh = _free(u->proxyh);
259 /* Perform one-time FTP initialization */
260 if (u->urltype == URL_IS_FTP) {
262 if (mustAsk || (u->user != NULL && u->password == NULL)) {
263 const char * host = (u->host ? u->host : "");
264 const char * user = (u->user ? u->user : "");
266 prompt = alloca(strlen(host) + strlen(user) + 256);
267 sprintf(prompt, _("Password for %s@%s: "), user, host);
268 u->password = _free(u->password);
269 /*@-dependenttrans -moduncon @*/
270 u->password = /*@-unrecog@*/ getpass(prompt) /*@=unrecog@*/;
271 /*@=dependenttrans =moduncon @*/
273 u->password = xstrdup(u->password);
276 if (u->proxyh == NULL) {
277 const char *proxy = rpmExpand("%{_ftpproxy}", NULL);
278 if (proxy && *proxy != '%') {
279 /*@observer@*/ const char * host = (u->host ? u->host : "");
280 const char *uu = (u->user ? u->user : "anonymous");
281 char *nu = xmalloc(strlen(uu) + sizeof("@") + strlen(host));
282 (void) stpcpy( stpcpy( stpcpy(nu, uu), "@"), host);
284 u->proxyh = xstrdup(proxy);
286 proxy = _free(proxy);
290 const char *proxy = rpmExpand("%{_ftpport}", NULL);
291 if (proxy && *proxy != '%') {
293 int port = strtol(proxy, &end, 0);
294 if (!(end && *end == '\0')) {
295 fprintf(stderr, _("error: %sport must be a number\n"),
296 (u->service ? u->service : ""));
301 proxy = _free(proxy);
305 /* Perform one-time HTTP initialization */
306 if (u->urltype == URL_IS_HTTP) {
308 if (u->proxyh == NULL) {
309 const char *proxy = rpmExpand("%{_httpproxy}", NULL);
310 if (proxy && *proxy != '%')
311 u->proxyh = xstrdup(proxy);
312 proxy = _free(proxy);
316 const char *proxy = rpmExpand("%{_httpport}", NULL);
317 if (proxy && *proxy != '%') {
319 int port = strtol(proxy, &end, 0);
320 if (!(end && *end == '\0')) {
321 fprintf(stderr, _("error: %sport must be a number\n"),
322 (u->service ? u->service : ""));
327 proxy = _free(proxy);
339 /*@observer@*/ /*@unchecked@*/
340 static struct urlstring {
341 /*@observer@*/ /*@null@*/
345 { "file://", URL_IS_PATH },
346 { "ftp://", URL_IS_FTP },
347 { "http://", URL_IS_HTTP },
348 { "-", URL_IS_DASH },
349 { NULL, URL_IS_UNKNOWN }
352 urltype urlIsURL(const char * url)
354 struct urlstring *us;
358 for (us = urlstrings; us->leadin != NULL; us++) {
359 if (strncmp(url, us->leadin, strlen(us->leadin)))
366 return URL_IS_UNKNOWN;
370 /* Return path portion of url (or pointer to NUL if url == NULL) */
371 urltype urlPath(const char * url, const char ** pathp)
377 urltype = urlIsURL(url);
381 url += sizeof("ftp://") - 1;
382 path = strchr(url, '/');
383 if (path == NULL) path = url + strlen(url);
387 url += sizeof("file://") - 1;
388 path = strchr(url, '/');
389 if (path == NULL) path = url + strlen(url);
392 if (path == NULL) path = "";
408 * Split URL into components. The URL can look like
409 * service://user:password@host:port/path
413 int urlSplit(const char * url, urlinfo *uret)
417 char *s, *se, *f, *fe;
421 if ((u = urlNew("urlSplit")) == NULL)
424 if ((se = s = myurl = xstrdup(url)) == NULL) {
425 u = urlFree(u, "urlSplit (error #1)");
429 u->url = xstrdup(url);
430 u->urltype = urlIsURL(url);
433 /* Point to end of next item */
434 while (*se && *se != '/') se++;
435 /* Item was service. Save service and go for the rest ...*/
436 if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
438 u->service = xstrdup(s);
439 se += 2; /* skip over "//" */
444 /* Item was everything-but-path. Continue parse on rest */
449 /* Look for ...@host... */
451 while (*fe && *fe != '@') fe++;
456 /* Look for user:password@host... */
457 while (fe > f && *fe != ':') fe--;
460 u->password = xstrdup(fe);
462 u->user = xstrdup(f);
466 /* Look for ...host:port */
468 while (*fe && *fe != ':') fe++;
471 u->portstr = xstrdup(fe);
472 if (u->portstr != NULL && u->portstr[0] != '\0') {
474 u->port = strtol(u->portstr, &end, 0);
475 if (!(end && *end == '\0')) {
476 rpmMessage(RPMMESS_ERROR, _("url port must be a number\n"));
477 myurl = _free(myurl);
478 u = urlFree(u, "urlSplit (error #3)");
483 u->host = xstrdup(f);
485 if (u->port < 0 && u->service != NULL) {
486 struct servent *serv;
487 /*@-multithreaded -moduncon @*/
488 serv = getservbyname(u->service, "tcp");
489 /*@=multithreaded =moduncon @*/
491 u->port = ntohs(serv->s_port);
492 else if (u->urltype == URL_IS_FTP)
493 u->port = IPPORT_FTP;
494 else if (u->urltype == URL_IS_HTTP)
495 u->port = IPPORT_HTTP;
498 myurl = _free(myurl);
501 /*@-globs -mods @*/ /* FIX: rpmGlobalMacroContext not in <rpmlib.h> */
510 int urlGetFile(const char * url, const char * dest)
515 const char * sfuPath = NULL;
516 int urlType = urlPath(url, &sfuPath);
518 if (*sfuPath == '\0')
519 return FTPERR_UNKNOWN;
521 sfd = Fopen(url, "r.ufdio");
522 if (sfd == NULL || Ferror(sfd)) {
523 rpmMessage(RPMMESS_DEBUG, _("failed to open %s: %s\n"), url, Fstrerror(sfd));
529 if ((dest = strrchr(sfuPath, '/')) != NULL)
536 return FTPERR_UNKNOWN;
538 tfd = Fopen(dest, "w.ufdio");
540 fprintf(stderr, "*** urlGetFile sfd %p %s tfd %p %s\n", sfd, url, (tfd ? tfd : NULL), dest);
541 if (tfd == NULL || Ferror(tfd)) {
543 rpmMessage(RPMMESS_DEBUG, _("failed to create %s: %s\n"), dest, Fstrerror(tfd));
554 if ((rc = ufdGetFile(sfd, tfd))) {
556 /* XXX FIXME: sfd possibly closed by copyData */
557 /*@-usereleased@*/ (void) Fclose(sfd) /*@=usereleased@*/ ;
559 sfd = NULL; /* XXX Fclose(sfd) done by ufdGetFile */