http protocol now uses tcp: protocol (simpler)
[libav.git] / libav / http.c
CommitLineData
de6d9b64
FB
1/*
2 * HTTP protocol for ffmpeg client
19720f15 3 * Copyright (c) 2000, 2001 Fabrice Bellard.
de6d9b64 4 *
19720f15
FB
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
de6d9b64 9 *
19720f15 10 * This library is distributed in the hope that it will be useful,
de6d9b64 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19720f15
FB
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
de6d9b64 14 *
19720f15
FB
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
de6d9b64 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 {
0e2a2197 39 URLContext *hd;
de6d9b64
FB
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
0e2a2197 46static int http_connect(URLContext *h, const char *path, const char *hoststr);
de6d9b64
FB
47static int http_write(URLContext *h, UINT8 *buf, int size);
48
0e2a2197 49
de6d9b64
FB
50/* return non zero if error */
51static int http_open(URLContext *h, const char *uri, int flags)
52{
0e2a2197
FB
53 const char *path, *proxy_path;
54 char hostname[1024], hoststr[1024];
55 char path1[1024];
56 char buf[1024];
57 int port, use_proxy, err;
de6d9b64 58 HTTPContext *s;
0e2a2197 59 URLContext *hd = NULL;
de6d9b64
FB
60
61 h->is_streamed = 1;
62
1ea4f593 63 s = av_malloc(sizeof(HTTPContext));
de6d9b64
FB
64 if (!s) {
65 return -ENOMEM;
66 }
67 h->priv_data = s;
68
69 proxy_path = getenv("http_proxy");
0e2a2197
FB
70 use_proxy = (proxy_path != NULL) && !getenv("no_proxy") &&
71 strstart(proxy_path, "http://", NULL);
de6d9b64
FB
72
73 /* fill the dest addr */
74 redo:
0e2a2197
FB
75 /* needed in any case to build the host string */
76 url_split(NULL, 0, hostname, sizeof(hostname), &port,
77 path1, sizeof(path1), uri);
78 if (port > 0) {
79 snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port);
de6d9b64 80 } else {
0e2a2197 81 pstrcpy(hoststr, sizeof(hoststr), hostname);
de6d9b64 82 }
0e2a2197 83
de6d9b64 84 if (use_proxy) {
0e2a2197
FB
85 url_split(NULL, 0, hostname, sizeof(hostname), &port,
86 NULL, 0, proxy_path);
de6d9b64
FB
87 path = uri;
88 } else {
0e2a2197 89 if (path1[0] == '\0')
de6d9b64
FB
90 path = "/";
91 else
0e2a2197 92 path = path1;
de6d9b64 93 }
0e2a2197
FB
94 if (port < 0)
95 port = 80;
de6d9b64 96
0e2a2197
FB
97 snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
98 err = url_open(&hd, buf, URL_RDWR);
99 if (err < 0)
de6d9b64
FB
100 goto fail;
101
0e2a2197
FB
102 s->hd = hd;
103 if (http_connect(h, path, hoststr) < 0)
de6d9b64
FB
104 goto fail;
105 if (s->http_code == 303 && s->location[0] != '\0') {
106 /* url moved, get next */
107 uri = s->location;
0e2a2197 108 url_close(hd);
de6d9b64
FB
109 goto redo;
110 }
de6d9b64
FB
111 return 0;
112 fail:
0e2a2197
FB
113 if (hd)
114 url_close(hd);
1ea4f593 115 av_free(s);
de6d9b64
FB
116 return -EIO;
117}
118
119static int http_getc(HTTPContext *s)
120{
121 int len;
122 if (s->buf_ptr >= s->buf_end) {
0e2a2197 123 len = url_read(s->hd, s->buffer, BUFFER_SIZE);
de6d9b64 124 if (len < 0) {
de6d9b64
FB
125 return -EIO;
126 } else if (len == 0) {
127 return -1;
128 } else {
129 s->buf_ptr = s->buffer;
130 s->buf_end = s->buffer + len;
131 }
132 }
133 return *s->buf_ptr++;
134}
135
136static int process_line(HTTPContext *s, char *line, int line_count)
137{
138 char *tag, *p;
139
140 /* end of header */
141 if (line[0] == '\0')
142 return 0;
143
144 p = line;
145 if (line_count == 0) {
146 while (!isspace(*p) && *p != '\0')
147 p++;
148 while (isspace(*p))
149 p++;
150 s->http_code = strtol(p, NULL, 10);
151#ifdef DEBUG
152 printf("http_code=%d\n", s->http_code);
153#endif
154 } else {
155 while (*p != '\0' && *p != ':')
156 p++;
157 if (*p != ':')
158 return 1;
159
160 *p = '\0';
161 tag = line;
162 p++;
163 while (isspace(*p))
164 p++;
165 if (!strcmp(tag, "Location")) {
166 strcpy(s->location, p);
167 }
168 }
169 return 1;
170}
171
0e2a2197 172static int http_connect(URLContext *h, const char *path, const char *hoststr)
de6d9b64
FB
173{
174 HTTPContext *s = h->priv_data;
175 int post, err, ch;
176 char line[1024], *q;
177
178
179 /* send http header */
180 post = h->flags & URL_WRONLY;
181
182 snprintf(s->buffer, sizeof(s->buffer),
183 "%s %s HTTP/1.0\n"
184 "User-Agent: FFmpeg %s\n"
185 "Accept: */*\n"
0e2a2197 186 "Host: %s\n"
de6d9b64
FB
187 "\n",
188 post ? "POST" : "GET",
189 path,
0e2a2197
FB
190 FFMPEG_VERSION,
191 hoststr);
192
de6d9b64
FB
193 if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
194 return -EIO;
195
196 /* init input buffer */
197 s->buf_ptr = s->buffer;
198 s->buf_end = s->buffer;
199 s->line_count = 0;
200 s->location[0] = '\0';
ddceb31d
PG
201 if (post) {
202 sleep(1);
de6d9b64 203 return 0;
ddceb31d 204 }
de6d9b64
FB
205
206 /* wait for header */
207 q = line;
208 for(;;) {
209 ch = http_getc(s);
210 if (ch < 0)
211 return -EIO;
212 if (ch == '\n') {
213 /* process line */
214 if (q > line && q[-1] == '\r')
215 q--;
216 *q = '\0';
217#ifdef DEBUG
218 printf("header='%s'\n", line);
219#endif
220 err = process_line(s, line, s->line_count);
221 if (err < 0)
222 return err;
223 if (err == 0)
224 return 0;
225 s->line_count++;
226 q = line;
227 } else {
228 if ((q - line) < sizeof(line) - 1)
229 *q++ = ch;
230 }
231 }
232}
233
234
235static int http_read(URLContext *h, UINT8 *buf, int size)
236{
237 HTTPContext *s = h->priv_data;
238 int size1, len;
239
240 size1 = size;
241 while (size > 0) {
242 /* read bytes from input buffer first */
243 len = s->buf_end - s->buf_ptr;
244 if (len > 0) {
245 if (len > size)
246 len = size;
247 memcpy(buf, s->buf_ptr, len);
248 s->buf_ptr += len;
249 } else {
0e2a2197 250 len = url_read (s->hd, buf, size);
de6d9b64 251 if (len < 0) {
0e2a2197 252 return len;
de6d9b64
FB
253 } else if (len == 0) {
254 break;
255 }
256 }
257 size -= len;
258 buf += len;
259 }
260 return size1 - size;
261}
262
263/* used only when posting data */
264static int http_write(URLContext *h, UINT8 *buf, int size)
265{
266 HTTPContext *s = h->priv_data;
0e2a2197 267 return url_write(s->hd, buf, size);
de6d9b64
FB
268}
269
270static int http_close(URLContext *h)
271{
272 HTTPContext *s = h->priv_data;
0e2a2197
FB
273 url_close(s->hd);
274 av_free(s);
de6d9b64
FB
275 return 0;
276}
277
278URLProtocol http_protocol = {
279 "http",
280 http_open,
281 http_read,
282 http_write,
283 NULL, /* seek */
284 http_close,
285};
0e2a2197 286