Lose bunch of unused fields from FD_t
[platform/upstream/rpm.git] / rpmio / url.c
1 /** \ingroup rpmio
2  * \file rpmio/url.c
3  */
4
5 #include "system.h"
6
7 #include <assert.h>
8 #include <netinet/in.h>
9
10 #include <rpm/rpmmacro.h>
11 #include <rpm/rpmlog.h>
12 #include <rpm/rpmurl.h>
13 #include <rpm/rpmio.h>
14 #include <rpm/argv.h>
15 #include <rpm/rpmstring.h>
16
17 #include "debug.h"
18
19 #ifndef IPPORT_FTP
20 #define IPPORT_FTP      21
21 #endif
22 #ifndef IPPORT_HTTP
23 #define IPPORT_HTTP     80
24 #endif
25 #ifndef IPPORT_HTTPS
26 #define IPPORT_HTTPS    443
27 #endif
28 #ifndef IPPORT_PGPKEYSERVER
29 #define IPPORT_PGPKEYSERVER     11371
30 #endif
31
32 #define URLMAGIC        0xd00b1ed0
33 #define URLSANE(u)      assert(u && u->magic == URLMAGIC)
34
35 /**
36  */
37 int _url_debug = 0;
38
39 urlinfo urlNew()
40 {
41     urlinfo u;
42     if ((u = xmalloc(sizeof(*u))) == NULL)
43         return NULL;
44     memset(u, 0, sizeof(*u));
45     u->proxyp = -1;
46     u->port = -1;
47     u->urltype = URL_IS_UNKNOWN;
48     u->magic = URLMAGIC;
49     return u;
50 }
51
52 urlinfo urlFree(urlinfo u)
53 {
54     URLSANE(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);
63
64     u = _free(u);
65     return NULL;
66 }
67
68 /**
69  */
70 static struct urlstring {
71     const char const * leadin;
72     urltype     ret;
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 },
79     { "-",              URL_IS_DASH },
80     { NULL,             URL_IS_UNKNOWN }
81 };
82
83 urltype urlIsURL(const char * url)
84 {
85     const struct urlstring *us;
86
87     if (url && *url) {
88         for (us = urlstrings; us->leadin != NULL; us++) {
89             if (strncmp(url, us->leadin, strlen(us->leadin)))
90                 continue;
91             return us->ret;
92         }
93     }
94
95     return URL_IS_UNKNOWN;
96 }
97
98 /* Return path portion of url (or pointer to NUL if url == NULL) */
99 urltype urlPath(const char * url, const char ** pathp)
100 {
101     const char *path;
102     int urltype;
103
104     path = url;
105     urltype = urlIsURL(url);
106     switch (urltype) {
107     case URL_IS_FTP:
108         url += sizeof("ftp://") - 1;
109         path = strchr(url, '/');
110         if (path == NULL) path = url + strlen(url);
111         break;
112     case URL_IS_PATH:
113         url += sizeof("file://") - 1;
114         path = strchr(url, '/');
115         if (path == NULL) path = url + strlen(url);
116         break;
117     case URL_IS_HKP:
118         url += sizeof("hkp://") - 1;
119         path = strchr(url, '/');
120         if (path == NULL) path = url + strlen(url);
121         break;
122     case URL_IS_HTTP:
123         url += sizeof("http://") - 1;
124         path = strchr(url, '/');
125         if (path == NULL) path = url + strlen(url);
126         break;
127     case URL_IS_HTTPS:
128         url += sizeof("https://") - 1;
129         path = strchr(url, '/');
130         if (path == NULL) path = url + strlen(url);
131         break;
132     case URL_IS_UNKNOWN:
133         if (path == NULL) path = "";
134         break;
135     case URL_IS_DASH:
136         path = "";
137         break;
138     }
139     if (pathp)
140         *pathp = path;
141     return urltype;
142 }
143
144 /*
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
149  */
150 int urlSplit(const char * url, urlinfo *uret)
151 {
152     urlinfo u;
153     char *myurl;
154     char *s, *se, *f, *fe;
155
156     if (uret == NULL)
157         return -1;
158     if ((u = urlNew()) == NULL)
159         return -1;
160
161     if ((se = s = myurl = xstrdup(url)) == NULL) {
162         u = urlFree(u);
163         return -1;
164     }
165
166     u->url = xstrdup(url);
167     u->urltype = urlIsURL(url);
168
169     while (1) {
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] == '/') {
174                 se[-1] = '\0';
175             u->scheme = xstrdup(s);
176             se += 2;    /* skip over "//" */
177             s = se++;
178             continue;
179         }
180         
181         /* Item was everything-but-path. Continue parse on rest */
182         *se = '\0';
183         break;
184     }
185
186     /* Look for ...@host... */
187     fe = f = s;
188     while (*fe && *fe != '@') fe++;
189     if (*fe == '@') {
190         s = fe + 1;
191         *fe = '\0';
192         /* Look for user:password@host... */
193         while (fe > f && *fe != ':') fe--;
194         if (*fe == ':') {
195             *fe++ = '\0';
196             u->password = xstrdup(fe);
197         }
198         u->user = xstrdup(f);
199     }
200
201     /* Look for ...host:port or [v6addr]:port*/
202     fe = f = s;
203     if (strchr(fe, '[') && strchr(fe, ']'))
204     {
205             fe = strchr(f, ']');
206             *f++ = '\0';
207             *fe++ = '\0';
208     }
209     while (*fe && *fe != ':') fe++;
210     if (*fe == ':') {
211         *fe++ = '\0';
212         u->portstr = xstrdup(fe);
213         if (u->portstr != NULL && u->portstr[0] != '\0') {
214             char *end;
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);
219                 u = urlFree(u);
220                 return -1;
221             }
222         }
223     }
224     u->host = xstrdup(f);
225
226     if (u->port < 0 && u->scheme != NULL) {
227         struct servent *serv;
228         /* HACK hkp:// might lookup "pgpkeyserver" */
229         serv = getservbyname(u->scheme, "tcp");
230         if (serv != NULL)
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;
240     }
241
242     myurl = _free(myurl);
243     if (uret) {
244         *uret = u;
245     }
246     return 0;
247 }
248
249
250 int urlGetFile(const char * url, const char * dest)
251 {
252     char *cmd = NULL;
253     const char *target = NULL;
254     char *urlhelper = NULL;
255     int rc;
256     pid_t pid, wait;
257
258     urlhelper = rpmExpand("%{?_urlhelper}", NULL);
259
260     if (dest == NULL) {
261         urlPath(url, &target);
262     } else {
263         target = dest;
264     }
265
266     /* XXX TODO: sanity checks like target == dest... */
267
268     rasprintf(&cmd, "%s %s %s\n", urlhelper, target, url);
269     urlhelper = _free(urlhelper);
270
271     if ((pid = fork()) == 0) {
272         ARGV_t argv = NULL;
273         argvSplit(&argv, cmd, " ");
274         execvp(argv[0], argv);
275         exit(-1); /* error out if exec fails */
276     }
277     wait = waitpid(pid, &rc, 0);
278     cmd = _free(cmd);
279
280     return rc;
281
282 }