xref: /freebsd/lib/libfetch/fetch.c (revision 11afcc8f9f96d657b8e6f7547c02c1957331fc96)
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.1.1.1 1998/07/09 16:52:42 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 /* get URL */
55 FILE *
56 fetchGetURL(char *URL, char *flags)
57 {
58     url_t *u;
59     FILE *f;
60 
61     /* parse URL */
62     if ((u = fetchParseURL(URL)) == NULL)
63 	return NULL;
64 
65     /* select appropriate function */
66     if (strcasecmp(u->scheme, "file") == 0)
67 	f = fetchGetFile(u, flags);
68     else if (strcasecmp(u->scheme, "http") == 0)
69 	f = fetchGetHTTP(u, flags);
70     else if (strcasecmp(u->scheme, "ftp") == 0)
71 	f = fetchGetFTP(u, flags);
72     else f = NULL;
73 
74     fetchFreeURL(u);
75     return f;
76 }
77 
78 
79 /* put URL */
80 FILE *
81 fetchPutURL(char *URL, char *flags)
82 {
83     url_t *u;
84     FILE *f;
85 
86     /* parse URL */
87     if ((u = fetchParseURL(URL)) == NULL)
88 	return NULL;
89 
90     /* select appropriate function */
91     if (strcasecmp(u->scheme, "file") == 0)
92 	f = fetchPutFile(u, flags);
93     else if (strcasecmp(u->scheme, "http") == 0)
94 	f = fetchPutHTTP(u, flags);
95     else if (strcasecmp(u->scheme, "ftp") == 0)
96 	f = fetchPutFTP(u, flags);
97     else f = NULL;
98 
99     fetchFreeURL(u);
100     return f;
101 }
102 
103 /*
104  * Split an URL into components. URL syntax is:
105  * method:[//[user[:pwd]@]host[:port]]/[document]
106  * This almost, but not quite, RFC1738 URL syntax.
107  */
108 url_t *
109 fetchParseURL(char *URL)
110 {
111     char *p, *q;
112     url_t *u;
113     int i;
114 
115     /* allocate url_t */
116     if ((u = calloc(1, sizeof(url_t))) == NULL)
117 	return NULL;
118 
119     /* scheme name */
120     for (i = 0; *URL && (*URL != ':'); URL++)
121 	if (i < URL_SCHEMELEN)
122 	    u->scheme[i++] = *URL;
123     if (!URL[0] || (URL[1] != '/'))
124 	goto ouch;
125     else URL++;
126     if (URL[1] != '/') {
127 	p = URL;
128 	goto nohost;
129     }
130     else URL += 2;
131 
132     p = strpbrk(URL, "/@");
133     if (*p == '@') {
134 	/* username */
135 	for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++)
136 	    if (i < URL_USERLEN)
137 		u->user[i++] = *q;
138 
139 	/* password */
140 	if (*q == ':')
141 	    for (q++, i = 0; (*q != ':') && (*q != '@'); q++)
142 		if (i < URL_PWDLEN)
143 		    u->pwd[i++] = *q;
144 
145 	p++;
146     } else p = URL;
147 
148     /* hostname */
149     for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
150 	if (i < MAXHOSTNAMELEN)
151 	    u->host[i++] = *p;
152 
153     /* port */
154     if (*p == ':') {
155 	for (q = ++p; *q && (*q != '/'); q++)
156 	    if (isdigit(*q))
157 		u->port = u->port * 10 + (*q - '0');
158 	    else return 0; /* invalid port */
159 	while (*p && (*p != '/'))
160 	    p++;
161     }
162 
163 nohost:
164     /* document */
165     if (*p)
166 	u->doc = strdup(p);
167     u->doc = strdup(*p ? p : "/");
168     if (!u->doc)
169 	goto ouch;
170 
171     DEBUG(fprintf(stderr,
172 		  "scheme:   [\033[1m%s\033[m]\n"
173 		  "user:     [\033[1m%s\033[m]\n"
174 		  "password: [\033[1m%s\033[m]\n"
175 		  "host:     [\033[1m%s\033[m]\n"
176 		  "port:     [\033[1m%d\033[m]\n"
177 		  "document: [\033[1m%s\033[m]\n",
178 		  u->scheme, u->user, u->pwd,
179 		  u->host, u->port, u->doc));
180 
181     return u;
182 
183 ouch:
184     free(u);
185     return NULL;
186 }
187 
188 void
189 fetchFreeURL(url_t *u)
190 {
191     if (u) {
192 	if (u->doc)
193 	    free(u->doc);
194 	free(u);
195     }
196 }
197 
198 int
199 fetchConnect(char *host, int port)
200 {
201     struct sockaddr_in sin;
202     struct hostent *he;
203     int sd;
204 
205     /* look up host name */
206     if ((he = gethostbyname(host)) == NULL)
207 	return -1;
208 
209     /* set up socket address structure */
210     bzero(&sin, sizeof(sin));
211     bcopy(he->h_addr, (char *)&sin.sin_addr, he->h_length);
212     sin.sin_family = he->h_addrtype;
213     sin.sin_port = htons(port);
214 
215     /* try to connect */
216     if ((sd = socket(sin.sin_family, SOCK_STREAM, IPPROTO_TCP)) < 0)
217 	return -1;
218     if (connect(sd, (struct sockaddr *)&sin, sizeof sin) < 0) {
219 	close(sd);
220 	return -1;
221     }
222 
223     return sd;
224 }
225