xref: /freebsd/lib/libfetch/fetch.c (revision a8445737e740901f5f2c8d24c12ef7fc8b00134e)
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 
51 int fetchLastErrCode;
52 const char *fetchLastErrText;
53 
54 FILE *
55 fetchGet(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 
67 FILE *
68 fetchPut(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 */
80 FILE *
81 fetchGetURL(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 */
97 FILE *
98 fetchPutURL(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  */
117 url_t *
118 fetchParseURL(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 
172 nohost:
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 
192 ouch:
193     free(u);
194     return NULL;
195 }
196 
197 void
198 fetchFreeURL(url_t *u)
199 {
200     if (u) {
201 	if (u->doc)
202 	    free(u->doc);
203 	free(u);
204     }
205 }
206 
207 int
208 fetchConnect(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