Deleted Added
sdiff udiff text old ( 60190 ) new ( 60376 )
full compact
1/*-
2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 * $FreeBSD: head/lib/libfetch/fetch.c 60190 2000-05-07 20:02:52Z des $
29 */
30
31#include <sys/param.h>
32#include <sys/errno.h>
33
34#include <ctype.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#include "fetch.h"
40#include "common.h"
41
42
43int fetchLastErrCode;
44int fetchTimeout;
45
46
47/*** Local data **************************************************************/
48
49/*
50 * Error messages for parser errors
51 */
52#define URL_MALFORMED 1
53#define URL_BAD_SCHEME 2
54#define URL_BAD_PORT 3
55static struct fetcherr _url_errlist[] = {
56 { URL_MALFORMED, FETCH_URL, "Malformed URL" },
57 { URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" },
58 { URL_BAD_PORT, FETCH_URL, "Invalid server port" },
59 { -1, FETCH_UNKNOWN, "Unknown parser error" }
60};
61
62
63/*** Public API **************************************************************/
64
65/*
66 * Select the appropriate protocol for the URL scheme, and return a
67 * read-only stream connected to the document referenced by the URL.
68 */
69FILE *
70fetchGet(struct url *URL, char *flags)
71{
72 if (strcasecmp(URL->scheme, "file") == 0)
73 return fetchGetFile(URL, flags);
74 else if (strcasecmp(URL->scheme, "http") == 0)
75 return fetchGetHTTP(URL, flags);
76 else if (strcasecmp(URL->scheme, "ftp") == 0)
77 return fetchGetFTP(URL, flags);
78 else {
79 _url_seterr(URL_BAD_SCHEME);
80 return NULL;
81 }
82}
83
84/*
85 * Select the appropriate protocol for the URL scheme, and return a
86 * write-only stream connected to the document referenced by the URL.
87 */
88FILE *
89fetchPut(struct url *URL, char *flags)
90{
91 if (strcasecmp(URL->scheme, "file") == 0)
92 return fetchPutFile(URL, flags);
93 else if (strcasecmp(URL->scheme, "http") == 0)
94 return fetchPutHTTP(URL, flags);
95 else if (strcasecmp(URL->scheme, "ftp") == 0)
96 return fetchPutFTP(URL, flags);
97 else {
98 _url_seterr(URL_BAD_SCHEME);
99 return NULL;
100 }
101}
102
103/*
104 * Select the appropriate protocol for the URL scheme, and return the
105 * size of the document referenced by the URL if it exists.
106 */
107int
108fetchStat(struct url *URL, struct url_stat *us, char *flags)
109{
110 if (strcasecmp(URL->scheme, "file") == 0)
111 return fetchStatFile(URL, us, flags);
112 else if (strcasecmp(URL->scheme, "http") == 0)
113 return fetchStatHTTP(URL, us, flags);
114 else if (strcasecmp(URL->scheme, "ftp") == 0)
115 return fetchStatFTP(URL, us, flags);
116 else {
117 _url_seterr(URL_BAD_SCHEME);
118 return -1;
119 }
120}
121
122/*
123 * Select the appropriate protocol for the URL scheme, and return a
124 * list of files in the directory pointed to by the URL.
125 */
126struct url_ent *
127fetchList(struct url *URL, char *flags)
128{
129 if (strcasecmp(URL->scheme, "file") == 0)
130 return fetchListFile(URL, flags);
131 else if (strcasecmp(URL->scheme, "http") == 0)
132 return fetchListHTTP(URL, flags);
133 else if (strcasecmp(URL->scheme, "ftp") == 0)
134 return fetchListFTP(URL, flags);
135 else {
136 _url_seterr(URL_BAD_SCHEME);
137 return NULL;
138 }
139}
140
141/*
142 * Attempt to parse the given URL; if successful, call fetchGet().
143 */
144FILE *
145fetchGetURL(char *URL, char *flags)
146{
147 struct url *u;
148 FILE *f;
149
150 if ((u = fetchParseURL(URL)) == NULL)
151 return NULL;
152
153 f = fetchGet(u, flags);
154
155 free(u);
156 return f;
157}
158
159
160/*
161 * Attempt to parse the given URL; if successful, call fetchPut().
162 */
163FILE *
164fetchPutURL(char *URL, char *flags)
165{
166 struct url *u;
167 FILE *f;
168
169 if ((u = fetchParseURL(URL)) == NULL)
170 return NULL;
171
172 f = fetchPut(u, flags);
173
174 free(u);
175 return f;
176}
177
178/*
179 * Attempt to parse the given URL; if successful, call fetchStat().
180 */
181int
182fetchStatURL(char *URL, struct url_stat *us, char *flags)
183{
184 struct url *u;
185 int s;
186
187 if ((u = fetchParseURL(URL)) == NULL)
188 return -1;
189
190 s = fetchStat(u, us, flags);
191
192 free(u);
193 return s;
194}
195
196/*
197 * Attempt to parse the given URL; if successful, call fetchList().
198 */
199struct url_ent *
200fetchListURL(char *URL, char *flags)
201{
202 struct url *u;
203 struct url_ent *ue;
204
205 if ((u = fetchParseURL(URL)) == NULL)
206 return NULL;
207
208 ue = fetchList(u, flags);
209
210 free(u);
211 return ue;
212}
213
214/*
215 * Split an URL into components. URL syntax is:
216 * method:[//[user[:pwd]@]host[:port]]/[document]
217 * This almost, but not quite, RFC1738 URL syntax.
218 */
219struct url *
220fetchParseURL(char *URL)
221{
222 char *p, *q;
223 struct url *u;
224 int i;
225
226 /* allocate struct url */
227 if ((u = calloc(1, sizeof *u)) == NULL) {
228 errno = ENOMEM;
229 _fetch_syserr();
230 return NULL;
231 }
232
233 /* scheme name */
234 for (i = 0; *URL && (*URL != ':'); URL++)
235 if (i < URL_SCHEMELEN)
236 u->scheme[i++] = *URL;
237 if (!URL[0] || (URL[1] != '/')) {
238 _url_seterr(URL_BAD_SCHEME);
239 goto ouch;
240 }
241 else URL++;
242 if (URL[1] != '/') {
243 p = URL;
244 goto nohost;
245 }
246 else URL += 2;
247
248 p = strpbrk(URL, "/@");
249 if (p && *p == '@') {
250 /* username */
251 for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
252 if (i < URL_USERLEN)
253 u->user[i++] = *q;
254
255 /* password */
256 if (*q == ':')
257 for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
258 if (i < URL_PWDLEN)
259 u->pwd[i++] = *q;
260
261 p++;
262 } else p = URL;
263
264 /* hostname */
265 for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
266 if (i < MAXHOSTNAMELEN)
267 u->host[i++] = *p;
268
269 /* port */
270 if (*p == ':') {
271 for (q = ++p; *q && (*q != '/'); q++)
272 if (isdigit(*q))
273 u->port = u->port * 10 + (*q - '0');
274 else {
275 /* invalid port */
276 _url_seterr(URL_BAD_PORT);
277 goto ouch;
278 }
279 while (*p && (*p != '/'))
280 p++;
281 }
282
283nohost:
284 /* document */
285 if (*p) {
286 struct url *t;
287 t = realloc(u, sizeof *u + strlen(p) - 1);
288 if (t == NULL) {
289 errno = ENOMEM;
290 _fetch_syserr();
291 goto ouch;
292 }
293 u = t;
294 strcpy(u->doc, p);
295 } else {
296 u->doc[0] = '/';
297 u->doc[1] = 0;
298 }
299
300 DEBUG(fprintf(stderr,
301 "scheme: [\033[1m%s\033[m]\n"
302 "user: [\033[1m%s\033[m]\n"
303 "password: [\033[1m%s\033[m]\n"
304 "host: [\033[1m%s\033[m]\n"
305 "port: [\033[1m%d\033[m]\n"
306 "document: [\033[1m%s\033[m]\n",
307 u->scheme, u->user, u->pwd,
308 u->host, u->port, u->doc));
309
310 return u;
311
312ouch:
313 free(u);
314 return NULL;
315}