1 /*
2     Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifdef HAVE_UNISTD_H
23 #include <unistd.h>
24 #endif /* HAVE_UNISTD_H */
25 #ifndef NO_STRING_H
26 #include <string.h>
27 #else
28 #include <strings.h>
29 #endif
30 #include <signal.h> /* for SIGALRM */
31 
32 #include "libarc/url.h"
33 #include "net.h"
34 
35 /* #define DEBUG */
36 
37 #ifdef HTTP_PROXY_HOST
38 char *url_http_proxy_host = HTTP_PROXY_HOST;
39 unsigned short url_http_proxy_port = HTTP_PROXY_PORT;
40 #else
41 char *url_http_proxy_host = NULL;
42 unsigned short url_http_proxy_port;
43 #endif /* HTTP_PROXY_HOST */
44 
45 
46 #define REQUEST_OFFSET 16
47 
48 #define ALARM_TIMEOUT 10
49 static VOLATILE int timeout_flag = 1;
50 
51 
52 typedef struct _URL_http
53 {
54     char common[sizeof(struct _URL)];
55 
56     FILE *fp;
57 } URL_http;
58 
59 static int name_http_check(char *url_string);
60 static long url_http_read(URL url, void *buff, long n);
61 static char *url_http_gets(URL url, char *buff, int n);
62 static int url_http_fgetc(URL url);
63 static void url_http_close(URL url);
64 
65 struct URL_module URL_module_http =
66 {
67     URL_http_t,
68     name_http_check,
69     NULL,
70     url_http_open,
71     NULL
72 };
73 
name_http_check(char * s)74 static int name_http_check(char *s)
75 {
76     if(strncmp(s, "http://", 7) == 0)
77 	return 1;
78     return 0;
79 }
80 
81 /*ARGSUSED*/
timeout(int sig)82 static void timeout(int sig)
83 {
84     timeout_flag = 1;
85 }
86 
url_http_open(char * name)87 URL url_http_open(char *name)
88 {
89     URL_http *url;
90     SOCKET fd;
91     char *host, *path = NULL, *p;
92     unsigned short port;
93     char buff[BUFSIZ];
94     char wwwserver[256];
95     int n;
96 
97 #ifdef DEBUG
98     printf("url_http_open(%s)\n", name);
99 #endif /* DEBUG */
100 
101     url = (URL_http *)alloc_url(sizeof(URL_http));
102     if(url == NULL)
103     {
104 	url_errno = errno;
105 	return NULL;
106     }
107 
108     /* common members */
109     URLm(url, type)      = URL_http_t;
110     URLm(url, url_read)  = url_http_read;
111     URLm(url, url_gets)  = url_http_gets;
112     URLm(url, url_fgetc) = url_http_fgetc;
113     URLm(url, url_seek)  = NULL;
114     URLm(url, url_tell)  = NULL;
115     URLm(url, url_close) = url_http_close;
116 
117     /* private members */
118     url->fp = NULL;
119 
120     if(url_http_proxy_host)
121     {
122 	char *q;
123 	int len;
124 
125 	host = url_http_proxy_host;
126 	port = url_http_proxy_port;
127 
128 	p = name;
129 	if(strncmp(p, "http://", 7) == 0)
130 	    p += 7;
131 	for(q = p; *q && *q != ':' && *q != '/'; q++)
132 	    ;
133 	len = q - p;
134 	if(len >= sizeof(wwwserver) - 1) { /* What?? */
135 	    strcpy(wwwserver, "localhost");
136 	} else {
137 	    strncpy(wwwserver, p, len);
138 	}
139     }
140     else
141     {
142 	if(strncmp(name, "http://", 7) == 0)
143 	    name += 7;
144 	n = strlen(name);
145 	if(n + REQUEST_OFFSET >= BUFSIZ)
146 	{
147 	    url_http_close((URL)url);
148 	    url_errno = URLERR_URLTOOLONG;
149 	    errno = ENOENT;
150 	    return NULL;
151 	}
152 
153 	memcpy(buff, name, n + 1);
154 
155 	host = buff;
156 	for(p = host; *p && *p != ':' && *p != '/'; p++)
157 	    ;
158 	if(*p == ':')
159 	{
160 	    char *pp;
161 
162 	    *p++ = '\0'; /* terminate `host' string */
163 	    port = atoi(p);
164 	    pp = strchr(p, '/');
165 	    if(pp == NULL)
166 		p[0] = '\0';
167 	    else
168 		p = pp;
169 	}
170 	else
171 	    port = 80;
172 	path = p;
173 
174 	if(*path == '\0')
175 	    *(path + 1) = '\0';
176 
177 	*path = '\0'; /* terminate `host' string */
178 	strncpy(wwwserver, host, sizeof(wwwserver));
179     }
180 
181 #ifdef DEBUG
182     printf("open(host=`%s', port=`%d')\n", host, port);
183 #endif /* DEBUG */
184 
185 #ifdef __W32__
186     timeout_flag = 0;
187     fd = open_socket(host, port);
188 #else
189     timeout_flag = 0;
190     signal(SIGALRM, timeout);
191     alarm(ALARM_TIMEOUT);
192     fd = open_socket(host, port);
193     alarm(0);
194     signal(SIGALRM, SIG_DFL);
195 #endif /* __W32__ */
196 
197     if(fd  == (SOCKET)-1)
198     {
199 	VOLATILE_TOUCH(timeout_flag);
200 #ifdef ETIMEDOUT
201 	if(timeout_flag)
202 	    errno = ETIMEDOUT;
203 #endif /* ETIMEDOUT */
204 	if(errno)
205 	    url_errno = errno;
206 	else
207 	{
208 	    url_errno = URLERR_CANTOPEN;
209 	    errno = ENOENT;
210 	}
211 	url_http_close((URL)url);
212 	return NULL;
213     }
214 
215     if((url->fp = socket_fdopen(fd, "rb")) == NULL)
216     {
217 	url_errno = errno;
218 	closesocket(fd);
219 	url_http_close((URL)url);
220 	errno = url_errno;
221 	return NULL;
222     }
223 
224     if(url_http_proxy_host)
225 	sprintf(buff, "GET %s HTTP/1.0\r\n", name);
226     else
227     {
228 	*path = '/';
229 	sprintf(buff, "GET %s HTTP/1.0\r\n", path);
230     }
231     socket_write(fd, buff, (long)strlen(buff));
232 
233 #ifdef DEBUG
234     printf("HTTP<%s", buff);
235 #endif /* DEBUG */
236 
237     if(url_user_agent)
238     {
239 	sprintf(buff, "User-Agent: %s\r\n", url_user_agent);
240 	socket_write(fd, buff, (long)strlen(buff));
241 #ifdef DEBUG
242 	printf("HTTP<%s", buff);
243 #endif /* DEBUG */
244     }
245 
246     /* Host field */
247     sprintf(buff, "Host: %s\r\n", wwwserver);
248     socket_write(fd, buff, (long)strlen(buff));
249 #ifdef DEBUG
250     printf("HTTP<%s", buff);
251 #endif /* DEBUG */
252 
253     /* End of header */
254     socket_write(fd, "\r\n", 2);
255     socket_shutdown(fd, 1);
256 
257     if(socket_fgets(buff, BUFSIZ, url->fp) == NULL)
258     {
259 	if(errno)
260 	    url_errno = errno;
261 	else
262 	{
263 	    url_errno = URLERR_CANTOPEN;
264 	    errno = ENOENT;
265 	}
266 	url_http_close((URL)url);
267 	return NULL;
268     }
269 
270 #ifdef DEBUG
271     printf("HTTP>%s", buff);
272 #endif /* DEBUG */
273 
274     p = buff;
275     if(strncmp(p, "HTTP/1.0 ", 9) == 0 || strncmp(p, "HTTP/1.1 ", 9) == 0)
276 	p += 9;
277     if(strncmp(p, "200", 3) != 0) /* Not success */
278     {
279 	url_http_close((URL)url);
280 	url_errno = errno = ENOENT;
281 	return NULL;
282     }
283 
284     /* Skip mime header */
285     while(socket_fgets(buff, BUFSIZ, url->fp) != NULL)
286     {
287 	if(buff[0] == '\n' || (buff[0] == '\r' && buff[1] == '\n'))
288 	    break; /* end of heaer */
289 #ifdef DEBUG
290 	printf("HTTP>%s", buff);
291 #endif /* DEBUG */
292     }
293 
294 #ifdef __W32__
295     return url_buff_open((URL)url, 1);
296 #else
297     return (URL)url;
298 #endif /* __W32__ */
299 }
300 
url_http_close(URL url)301 static void url_http_close(URL url)
302 {
303     URL_http *urlp = (URL_http *)url;
304     int save_errno = errno;
305     if(urlp->fp != NULL)
306 	socket_fclose(urlp->fp);
307     free(url);
308     errno = save_errno;
309 }
310 
url_http_read(URL url,void * buff,long n)311 static long url_http_read(URL url, void *buff, long n)
312 {
313     URL_http *urlp = (URL_http *)url;
314     return socket_fread(buff, n, urlp->fp);
315 }
316 
url_http_gets(URL url,char * buff,int n)317 static char *url_http_gets(URL url, char *buff, int n)
318 {
319     URL_http *urlp = (URL_http *)url;
320     return socket_fgets(buff, n, urlp->fp);
321 }
322 
url_http_fgetc(URL url)323 static int url_http_fgetc(URL url)
324 {
325     URL_http *urlp = (URL_http *)url;
326     int n;
327     unsigned char c;
328 
329     n = socket_fread(&c, 1, urlp->fp);
330     if(n <= 0)
331     {
332 	if(errno)
333 	    url_errno = errno;
334 	return EOF;
335     }
336     return (int)c;
337 }
338