8 #include <netinet/in.h>
10 #include <rpm/rpmmacro.h>
11 #include <rpm/rpmlog.h>
12 #include <rpm/rpmurl.h>
13 #include <rpm/rpmio.h>
15 #include <rpm/rpmstring.h>
23 #define IPPORT_HTTP 80
26 #define IPPORT_HTTPS 443
28 #ifndef IPPORT_PGPKEYSERVER
29 #define IPPORT_PGPKEYSERVER 11371
32 #define URLMAGIC 0xd00b1ed0
33 #define URLSANE(u) assert(u && u->magic == URLMAGIC)
42 if ((u = xmalloc(sizeof(*u))) == NULL)
44 memset(u, 0, sizeof(*u));
47 u->urltype = URL_IS_UNKNOWN;
52 urlinfo urlFree(urlinfo u)
55 u->url = _free(u->url);
56 u->scheme = _free(u->scheme);
57 u->user = _free(u->user);
58 u->password = _free(u->password);
59 u->host = _free(u->host);
60 u->portstr = _free(u->portstr);
61 u->proxyu = _free(u->proxyu);
62 u->proxyh = _free(u->proxyh);
70 static struct urlstring {
71 const char const * leadin;
73 } const urlstrings[] = {
74 { "file://", URL_IS_PATH },
75 { "ftp://", URL_IS_FTP },
76 { "hkp://", URL_IS_HKP },
77 { "http://", URL_IS_HTTP },
78 { "https://", URL_IS_HTTPS },
80 { NULL, URL_IS_UNKNOWN }
83 urltype urlIsURL(const char * url)
85 const struct urlstring *us;
88 for (us = urlstrings; us->leadin != NULL; us++) {
89 if (strncmp(url, us->leadin, strlen(us->leadin)))
95 return URL_IS_UNKNOWN;
98 /* Return path portion of url (or pointer to NUL if url == NULL) */
99 urltype urlPath(const char * url, const char ** pathp)
105 urltype = urlIsURL(url);
108 url += sizeof("ftp://") - 1;
109 path = strchr(url, '/');
110 if (path == NULL) path = url + strlen(url);
113 url += sizeof("file://") - 1;
114 path = strchr(url, '/');
115 if (path == NULL) path = url + strlen(url);
118 url += sizeof("hkp://") - 1;
119 path = strchr(url, '/');
120 if (path == NULL) path = url + strlen(url);
123 url += sizeof("http://") - 1;
124 path = strchr(url, '/');
125 if (path == NULL) path = url + strlen(url);
128 url += sizeof("https://") - 1;
129 path = strchr(url, '/');
130 if (path == NULL) path = url + strlen(url);
133 if (path == NULL) path = "";
145 * Split URL into components. The URL can look like
146 * scheme://user:password@host:port/path
147 * or as in RFC2732 for IPv6 address
148 * service://user:password@[ip:v6:ad:dr:es:s]:port/path
150 int urlSplit(const char * url, urlinfo *uret)
154 char *s, *se, *f, *fe;
158 if ((u = urlNew()) == NULL)
161 if ((se = s = myurl = xstrdup(url)) == NULL) {
166 u->url = xstrdup(url);
167 u->urltype = urlIsURL(url);
170 /* Point to end of next item */
171 while (*se && *se != '/') se++;
172 /* Item was scheme. Save scheme and go for the rest ...*/
173 if (*se && (se != s) && se[-1] == ':' && se[0] == '/' && se[1] == '/') {
175 u->scheme = xstrdup(s);
176 se += 2; /* skip over "//" */
181 /* Item was everything-but-path. Continue parse on rest */
186 /* Look for ...@host... */
188 while (*fe && *fe != '@') fe++;
192 /* Look for user:password@host... */
193 while (fe > f && *fe != ':') fe--;
196 u->password = xstrdup(fe);
198 u->user = xstrdup(f);
201 /* Look for ...host:port or [v6addr]:port*/
203 if (strchr(fe, '[') && strchr(fe, ']'))
209 while (*fe && *fe != ':') fe++;
212 u->portstr = xstrdup(fe);
213 if (u->portstr != NULL && u->portstr[0] != '\0') {
215 u->port = strtol(u->portstr, &end, 0);
216 if (!(end && *end == '\0')) {
217 rpmlog(RPMLOG_ERR, _("url port must be a number\n"));
218 myurl = _free(myurl);
224 u->host = xstrdup(f);
226 if (u->port < 0 && u->scheme != NULL) {
227 struct servent *serv;
228 /* HACK hkp:// might lookup "pgpkeyserver" */
229 serv = getservbyname(u->scheme, "tcp");
231 u->port = ntohs(serv->s_port);
232 else if (u->urltype == URL_IS_FTP)
233 u->port = IPPORT_FTP;
234 else if (u->urltype == URL_IS_HKP)
235 u->port = IPPORT_PGPKEYSERVER;
236 else if (u->urltype == URL_IS_HTTP)
237 u->port = IPPORT_HTTP;
238 else if (u->urltype == URL_IS_HTTPS)
239 u->port = IPPORT_HTTPS;
242 myurl = _free(myurl);
250 int urlGetFile(const char * url, const char * dest)
253 const char *target = NULL;
254 char *urlhelper = NULL;
258 urlhelper = rpmExpand("%{?_urlhelper}", NULL);
261 urlPath(url, &target);
266 /* XXX TODO: sanity checks like target == dest... */
268 rasprintf(&cmd, "%s %s %s\n", urlhelper, target, url);
269 urlhelper = _free(urlhelper);
271 if ((pid = fork()) == 0) {
273 argvSplit(&argv, cmd, " ");
274 execvp(argv[0], argv);
275 exit(-1); /* error out if exec fails */
277 wait = waitpid(pid, &rc, 0);