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