fetch.c revision 38394
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 *	$Id: fetch.c,v 1.3 1998/07/11 21:29:07 des Exp $
29 */
30
31#include <sys/param.h>
32#include <sys/types.h>
33#include <sys/socket.h>
34#include <netinet/in.h>
35
36#include <ctype.h>
37#include <netdb.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#include "fetch.h"
44
45#ifndef NDEBUG
46#define DEBUG(x) do x; while (0)
47#else
48#define DEBUG(x) do { } while (0)
49#endif
50
51int fetchLastErrCode;
52const char *fetchLastErrText;
53
54FILE *
55fetchGet(url_t *URL, char *flags)
56{
57    if (strcasecmp(URL->scheme, "file") == 0)
58	return fetchGetFile(URL, flags);
59    else if (strcasecmp(URL->scheme, "http") == 0)
60	return fetchGetHTTP(URL, flags);
61    else if (strcasecmp(URL->scheme, "ftp") == 0)
62	return fetchGetFTP(URL, flags);
63    else return NULL;
64
65}
66
67FILE *
68fetchPut(url_t *URL, char *flags)
69{
70    if (strcasecmp(URL->scheme, "file") == 0)
71	return fetchPutFile(URL, flags);
72    else if (strcasecmp(URL->scheme, "http") == 0)
73	return fetchPutHTTP(URL, flags);
74    else if (strcasecmp(URL->scheme, "ftp") == 0)
75	return fetchPutFTP(URL, flags);
76    else return NULL;
77}
78
79/* get URL */
80FILE *
81fetchGetURL(char *URL, char *flags)
82{
83    url_t *u;
84    FILE *f;
85
86    if ((u = fetchParseURL(URL)) == NULL)
87	return NULL;
88
89    f = fetchGet(u, flags);
90
91    fetchFreeURL(u);
92    return f;
93}
94
95
96/* put URL */
97FILE *
98fetchPutURL(char *URL, char *flags)
99{
100    url_t *u;
101    FILE *f;
102
103    if ((u = fetchParseURL(URL)) == NULL)
104	return NULL;
105
106    f = fetchPut(u, flags);
107
108    fetchFreeURL(u);
109    return f;
110}
111
112/*
113 * Split an URL into components. URL syntax is:
114 * method:[//[user[:pwd]@]host[:port]]/[document]
115 * This almost, but not quite, RFC1738 URL syntax.
116 */
117url_t *
118fetchParseURL(char *URL)
119{
120    char *p, *q;
121    url_t *u;
122    int i;
123
124    /* allocate url_t */
125    if ((u = calloc(1, sizeof(url_t))) == NULL)
126	return NULL;
127
128    /* scheme name */
129    for (i = 0; *URL && (*URL != ':'); URL++)
130	if (i < URL_SCHEMELEN)
131	    u->scheme[i++] = *URL;
132    if (!URL[0] || (URL[1] != '/'))
133	goto ouch;
134    else URL++;
135    if (URL[1] != '/') {
136	p = URL;
137	goto nohost;
138    }
139    else URL += 2;
140
141    p = strpbrk(URL, "/@");
142    if (*p == '@') {
143	/* username */
144	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
145	    if (i < URL_USERLEN)
146		u->user[i++] = *q;
147
148	/* password */
149	if (*q == ':')
150	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
151		if (i < URL_PWDLEN)
152		    u->pwd[i++] = *q;
153
154	p++;
155    } else p = URL;
156
157    /* hostname */
158    for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
159	if (i < MAXHOSTNAMELEN)
160	    u->host[i++] = *p;
161
162    /* port */
163    if (*p == ':') {
164	for (q = ++p; *q && (*q != '/'); q++)
165	    if (isdigit(*q))
166		u->port = u->port * 10 + (*q - '0');
167	    else return 0; /* invalid port */
168	while (*p && (*p != '/'))
169	    p++;
170    }
171
172nohost:
173    /* document */
174    if (*p)
175	u->doc = strdup(p);
176    u->doc = strdup(*p ? p : "/");
177    if (!u->doc)
178	goto ouch;
179
180    DEBUG(fprintf(stderr,
181		  "scheme:   [\033[1m%s\033[m]\n"
182		  "user:     [\033[1m%s\033[m]\n"
183		  "password: [\033[1m%s\033[m]\n"
184		  "host:     [\033[1m%s\033[m]\n"
185		  "port:     [\033[1m%d\033[m]\n"
186		  "document: [\033[1m%s\033[m]\n",
187		  u->scheme, u->user, u->pwd,
188		  u->host, u->port, u->doc));
189
190    return u;
191
192ouch:
193    free(u);
194    return NULL;
195}
196
197void
198fetchFreeURL(url_t *u)
199{
200    if (u) {
201	if (u->doc)
202	    free(u->doc);
203	free(u);
204    }
205}
206
207int
208fetchConnect(char *host, int port)
209{
210    struct sockaddr_in sin;
211    struct hostent *he;
212    int sd;
213
214#ifndef NDEBUG
215    fprintf(stderr, "\033[1m---> %s:%d\033[m\n", host, port);
216#endif
217
218    /* look up host name */
219    if ((he = gethostbyname(host)) == NULL)
220	return -1;
221
222    /* set up socket address structure */
223    bzero(&sin, sizeof(sin));
224    bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
225    sin.sin_family = he->h_addrtype;
226    sin.sin_port = htons(port);
227
228    /* try to connect */
229    if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
230	return -1;
231    if (connect(sd, (struct sockaddr *)&sin, sizeof sin) == -1) {
232	close(sd);
233	return -1;
234    }
235
236    return sd;
237}
238