fixed double free - fixed probe function
[libav.git] / libav / http.c
CommitLineData
de6d9b64
FB
1/*
2 * HTTP protocol for ffmpeg client
3 * Copyright (c) 2000, 2001 Gerard Lantau.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
8be1c656 19#include "avformat.h"
de6d9b64 20#include <unistd.h>
de6d9b64
FB
21#include <ctype.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <netdb.h>
27
de6d9b64
FB
28
29/* XXX: POST protocol is not completly implemented because ffmpeg use
30 only a subset of it */
31
32//#define DEBUG
33
34/* used for protocol handling */
35#define BUFFER_SIZE 1024
36#define URL_SIZE 4096
37
38typedef struct {
39 int fd;
40 unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
41 int line_count;
42 int http_code;
43 char location[URL_SIZE];
44} HTTPContext;
45
46static int http_connect(URLContext *h, const char *path);
47static int http_write(URLContext *h, UINT8 *buf, int size);
48
49/* return non zero if error */
50static int http_open(URLContext *h, const char *uri, int flags)
51{
52 struct sockaddr_in dest_addr;
53 const char *p, *path, *proxy_path;
54 char hostname[1024], *q;
55 int port, fd = -1, use_proxy;
56 struct hostent *hp;
57 HTTPContext *s;
58
59 h->is_streamed = 1;
60
1ea4f593 61 s = av_malloc(sizeof(HTTPContext));
de6d9b64
FB
62 if (!s) {
63 return -ENOMEM;
64 }
65 h->priv_data = s;
66
67 proxy_path = getenv("http_proxy");
68 use_proxy = (proxy_path != NULL) && !getenv("no_proxy");
69
70 /* fill the dest addr */
71 redo:
72 if (use_proxy) {
73 p = proxy_path;
74 } else {
75 p = uri;
76 }
77 if (!strstart(p, "http://", &p))
78 goto fail;
79 q = hostname;
80 while (*p != ':' && *p != '/' && *p != '\0') {
81 if ((q - hostname) < sizeof(hostname) - 1)
82 *q++ = *p;
83 p++;
84 }
85 *q = '\0';
86 port = 80;
87 if (*p == ':') {
88 p++;
89 port = strtoul(p, (char **)&p, 10);
90 }
91 if (port <= 0)
92 goto fail;
93 if (use_proxy) {
94 path = uri;
95 } else {
96 if (*p == '\0')
97 path = "/";
98 else
99 path = p;
100 }
101
102 dest_addr.sin_family = AF_INET;
103 dest_addr.sin_port = htons(port);
104 if ((inet_aton(hostname, &dest_addr.sin_addr)) == 0) {
105 hp = gethostbyname(hostname);
106 if (!hp)
107 goto fail;
108 memcpy (&dest_addr.sin_addr, hp->h_addr, sizeof(dest_addr.sin_addr));
109 }
110
111 fd = socket(PF_INET, SOCK_STREAM, 0);
112 if (fd < 0)
113 goto fail;
114
115 if (connect(fd, (struct sockaddr *)&dest_addr,
116 sizeof(dest_addr)) < 0)
117 goto fail;
118
119 s->fd = fd;
120 if (http_connect(h, path) < 0)
121 goto fail;
122 if (s->http_code == 303 && s->location[0] != '\0') {
123 /* url moved, get next */
124 uri = s->location;
125 goto redo;
126 }
127
128 return 0;
129 fail:
130 if (fd >= 0)
131 close(fd);
1ea4f593 132 av_free(s);
de6d9b64
FB
133 return -EIO;
134}
135
136static int http_getc(HTTPContext *s)
137{
138 int len;
139 if (s->buf_ptr >= s->buf_end) {
140 redo:
141 len = read(s->fd, s->buffer, BUFFER_SIZE);
142 if (len < 0) {
143 if (errno == EAGAIN || errno == EINTR)
144 goto redo;
145 return -EIO;
146 } else if (len == 0) {
147 return -1;
148 } else {
149 s->buf_ptr = s->buffer;
150 s->buf_end = s->buffer + len;
151 }
152 }
153 return *s->buf_ptr++;
154}
155
156static int process_line(HTTPContext *s, char *line, int line_count)
157{
158 char *tag, *p;
159
160 /* end of header */
161 if (line[0] == '\0')
162 return 0;
163
164 p = line;
165 if (line_count == 0) {
166 while (!isspace(*p) && *p != '\0')
167 p++;
168 while (isspace(*p))
169 p++;
170 s->http_code = strtol(p, NULL, 10);
171#ifdef DEBUG
172 printf("http_code=%d\n", s->http_code);
173#endif
174 } else {
175 while (*p != '\0' && *p != ':')
176 p++;
177 if (*p != ':')
178 return 1;
179
180 *p = '\0';
181 tag = line;
182 p++;
183 while (isspace(*p))
184 p++;
185 if (!strcmp(tag, "Location")) {
186 strcpy(s->location, p);
187 }
188 }
189 return 1;
190}
191
192static int http_connect(URLContext *h, const char *path)
193{
194 HTTPContext *s = h->priv_data;
195 int post, err, ch;
196 char line[1024], *q;
197
198
199 /* send http header */
200 post = h->flags & URL_WRONLY;
201
202 snprintf(s->buffer, sizeof(s->buffer),
203 "%s %s HTTP/1.0\n"
204 "User-Agent: FFmpeg %s\n"
205 "Accept: */*\n"
206 "\n",
207 post ? "POST" : "GET",
208 path,
209 FFMPEG_VERSION
210 );
211
212 if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
213 return -EIO;
214
215 /* init input buffer */
216 s->buf_ptr = s->buffer;
217 s->buf_end = s->buffer;
218 s->line_count = 0;
219 s->location[0] = '\0';
ddceb31d
PG
220 if (post) {
221 sleep(1);
de6d9b64 222 return 0;
ddceb31d 223 }
de6d9b64
FB
224
225 /* wait for header */
226 q = line;
227 for(;;) {
228 ch = http_getc(s);
229 if (ch < 0)
230 return -EIO;
231 if (ch == '\n') {
232 /* process line */
233 if (q > line && q[-1] == '\r')
234 q--;
235 *q = '\0';
236#ifdef DEBUG
237 printf("header='%s'\n", line);
238#endif
239 err = process_line(s, line, s->line_count);
240 if (err < 0)
241 return err;
242 if (err == 0)
243 return 0;
244 s->line_count++;
245 q = line;
246 } else {
247 if ((q - line) < sizeof(line) - 1)
248 *q++ = ch;
249 }
250 }
251}
252
253
254static int http_read(URLContext *h, UINT8 *buf, int size)
255{
256 HTTPContext *s = h->priv_data;
257 int size1, len;
258
259 size1 = size;
260 while (size > 0) {
261 /* read bytes from input buffer first */
262 len = s->buf_end - s->buf_ptr;
263 if (len > 0) {
264 if (len > size)
265 len = size;
266 memcpy(buf, s->buf_ptr, len);
267 s->buf_ptr += len;
268 } else {
269 len = read (s->fd, buf, size);
270 if (len < 0) {
271 if (errno != EINTR && errno != EAGAIN)
272 return -errno;
273 else
274 continue;
275 } else if (len == 0) {
276 break;
277 }
278 }
279 size -= len;
280 buf += len;
281 }
282 return size1 - size;
283}
284
285/* used only when posting data */
286static int http_write(URLContext *h, UINT8 *buf, int size)
287{
288 HTTPContext *s = h->priv_data;
289 int ret, size1;
290
291 size1 = size;
292 while (size > 0) {
293 ret = write (s->fd, buf, size);
294 if (ret < 0 && errno != EINTR && errno != EAGAIN)
295 return -errno;
296 size -= ret;
297 buf += ret;
298 }
299 return size1 - size;
300}
301
302static int http_close(URLContext *h)
303{
304 HTTPContext *s = h->priv_data;
305 close(s->fd);
306 return 0;
307}
308
309URLProtocol http_protocol = {
310 "http",
311 http_open,
312 http_read,
313 http_write,
314 NULL, /* seek */
315 http_close,
316};