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