Statistics
| Branch: | Revision:

ffmpeg / libavformat / http.c @ 20f269dc

History | View | Annotate | Download (6.81 KB)

1 de6d9b64 Fabrice Bellard
/*
2
 * HTTP protocol for ffmpeg client
3 19720f15 Fabrice Bellard
 * Copyright (c) 2000, 2001 Fabrice Bellard.
4 de6d9b64 Fabrice Bellard
 *
5 19720f15 Fabrice Bellard
 * 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.
9 de6d9b64 Fabrice Bellard
 *
10 19720f15 Fabrice Bellard
 * This library is distributed in the hope that it will be useful,
11 de6d9b64 Fabrice Bellard
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 19720f15 Fabrice Bellard
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14 de6d9b64 Fabrice Bellard
 *
15 19720f15 Fabrice Bellard
 * 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
18 de6d9b64 Fabrice Bellard
 */
19 8be1c656 Fabrice Bellard
#include "avformat.h"
20 de6d9b64 Fabrice Bellard
#include <unistd.h>
21
#include <sys/types.h>
22 b8a78f41 Michael Niedermayer
#include <sys/socket.h>
23 de6d9b64 Fabrice Bellard
#include <netinet/in.h>
24 9ddd71fc Fran├žois Revol
#ifndef __BEOS__
25
# include <arpa/inet.h>
26
#else
27
# include "barpainet.h"
28
#endif
29 de6d9b64 Fabrice Bellard
#include <netdb.h>
30
31
32
/* XXX: POST protocol is not completly implemented because ffmpeg use
33
   only a subset of it */
34
35
//#define DEBUG
36
37
/* used for protocol handling */
38
#define BUFFER_SIZE 1024
39
#define URL_SIZE    4096
40
41
typedef struct {
42 0e2a2197 Fabrice Bellard
    URLContext *hd;
43 de6d9b64 Fabrice Bellard
    unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
44
    int line_count;
45
    int http_code;
46
    char location[URL_SIZE];
47
} HTTPContext;
48
49 0e2a2197 Fabrice Bellard
static int http_connect(URLContext *h, const char *path, const char *hoststr);
50 0c1a9eda Zdenek Kabelac
static int http_write(URLContext *h, uint8_t *buf, int size);
51 de6d9b64 Fabrice Bellard
52 0e2a2197 Fabrice Bellard
53 de6d9b64 Fabrice Bellard
/* return non zero if error */
54
static int http_open(URLContext *h, const char *uri, int flags)
55
{
56 0e2a2197 Fabrice Bellard
    const char *path, *proxy_path;
57
    char hostname[1024], hoststr[1024];
58
    char path1[1024];
59
    char buf[1024];
60
    int port, use_proxy, err;
61 de6d9b64 Fabrice Bellard
    HTTPContext *s;
62 0e2a2197 Fabrice Bellard
    URLContext *hd = NULL;
63 de6d9b64 Fabrice Bellard
64
    h->is_streamed = 1;
65
66 1ea4f593 Fabrice Bellard
    s = av_malloc(sizeof(HTTPContext));
67 de6d9b64 Fabrice Bellard
    if (!s) {
68
        return -ENOMEM;
69
    }
70
    h->priv_data = s;
71
72
    proxy_path = getenv("http_proxy");
73 0e2a2197 Fabrice Bellard
    use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && 
74
        strstart(proxy_path, "http://", NULL);
75 de6d9b64 Fabrice Bellard
76
    /* fill the dest addr */
77
 redo:
78 0e2a2197 Fabrice Bellard
    /* needed in any case to build the host string */
79
    url_split(NULL, 0, hostname, sizeof(hostname), &port, 
80
              path1, sizeof(path1), uri);
81
    if (port > 0) {
82
        snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port);
83 de6d9b64 Fabrice Bellard
    } else {
84 0e2a2197 Fabrice Bellard
        pstrcpy(hoststr, sizeof(hoststr), hostname);
85 de6d9b64 Fabrice Bellard
    }
86 0e2a2197 Fabrice Bellard
87 de6d9b64 Fabrice Bellard
    if (use_proxy) {
88 0e2a2197 Fabrice Bellard
        url_split(NULL, 0, hostname, sizeof(hostname), &port, 
89
                  NULL, 0, proxy_path);
90 de6d9b64 Fabrice Bellard
        path = uri;
91
    } else {
92 0e2a2197 Fabrice Bellard
        if (path1[0] == '\0')
93 de6d9b64 Fabrice Bellard
            path = "/";
94
        else
95 0e2a2197 Fabrice Bellard
            path = path1;
96 de6d9b64 Fabrice Bellard
    }
97 0e2a2197 Fabrice Bellard
    if (port < 0)
98
        port = 80;
99 de6d9b64 Fabrice Bellard
100 0e2a2197 Fabrice Bellard
    snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
101
    err = url_open(&hd, buf, URL_RDWR);
102
    if (err < 0)
103 de6d9b64 Fabrice Bellard
        goto fail;
104
105 0e2a2197 Fabrice Bellard
    s->hd = hd;
106
    if (http_connect(h, path, hoststr) < 0)
107 de6d9b64 Fabrice Bellard
        goto fail;
108
    if (s->http_code == 303 && s->location[0] != '\0') {
109
        /* url moved, get next */
110
        uri = s->location;
111 0e2a2197 Fabrice Bellard
        url_close(hd);
112 de6d9b64 Fabrice Bellard
        goto redo;
113
    }
114
    return 0;
115
 fail:
116 0e2a2197 Fabrice Bellard
    if (hd)
117
        url_close(hd);
118 1ea4f593 Fabrice Bellard
    av_free(s);
119 de6d9b64 Fabrice Bellard
    return -EIO;
120
}
121
122
static int http_getc(HTTPContext *s)
123
{
124
    int len;
125
    if (s->buf_ptr >= s->buf_end) {
126 0e2a2197 Fabrice Bellard
        len = url_read(s->hd, s->buffer, BUFFER_SIZE);
127 de6d9b64 Fabrice Bellard
        if (len < 0) {
128
            return -EIO;
129
        } else if (len == 0) {
130
            return -1;
131
        } else {
132
            s->buf_ptr = s->buffer;
133
            s->buf_end = s->buffer + len;
134
        }
135
    }
136
    return *s->buf_ptr++;
137
}
138
139
static int process_line(HTTPContext *s, char *line, int line_count)
140
{
141
    char *tag, *p;
142
    
143
    /* end of header */
144
    if (line[0] == '\0')
145
        return 0;
146
147
    p = line;
148
    if (line_count == 0) {
149
        while (!isspace(*p) && *p != '\0')
150
            p++;
151
        while (isspace(*p))
152
            p++;
153
        s->http_code = strtol(p, NULL, 10);
154
#ifdef DEBUG
155
        printf("http_code=%d\n", s->http_code);
156
#endif
157
    } else {
158
        while (*p != '\0' && *p != ':')
159
            p++;
160
        if (*p != ':') 
161
            return 1;
162
        
163
        *p = '\0';
164
        tag = line;
165
        p++;
166
        while (isspace(*p))
167
            p++;
168
        if (!strcmp(tag, "Location")) {
169
            strcpy(s->location, p);
170
        }
171
    }
172
    return 1;
173
}
174
175 0e2a2197 Fabrice Bellard
static int http_connect(URLContext *h, const char *path, const char *hoststr)
176 de6d9b64 Fabrice Bellard
{
177
    HTTPContext *s = h->priv_data;
178
    int post, err, ch;
179
    char line[1024], *q;
180
181
182
    /* send http header */
183
    post = h->flags & URL_WRONLY;
184
185
    snprintf(s->buffer, sizeof(s->buffer),
186
             "%s %s HTTP/1.0\n"
187
             "User-Agent: FFmpeg %s\n"
188
             "Accept: */*\n"
189 0e2a2197 Fabrice Bellard
             "Host: %s\n"
190 de6d9b64 Fabrice Bellard
             "\n",
191
             post ? "POST" : "GET",
192
             path,
193 ce2749d2 Alex Beregszaszi
             LIBAVFORMAT_VERSION,
194 0e2a2197 Fabrice Bellard
             hoststr);
195
    
196 de6d9b64 Fabrice Bellard
    if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
197
        return -EIO;
198
        
199
    /* init input buffer */
200
    s->buf_ptr = s->buffer;
201
    s->buf_end = s->buffer;
202
    s->line_count = 0;
203
    s->location[0] = '\0';
204 ddceb31d Philip Gladstone
    if (post) {
205
        sleep(1);
206 de6d9b64 Fabrice Bellard
        return 0;
207 ddceb31d Philip Gladstone
    }
208 de6d9b64 Fabrice Bellard
    
209
    /* wait for header */
210
    q = line;
211
    for(;;) {
212
        ch = http_getc(s);
213
        if (ch < 0)
214
            return -EIO;
215
        if (ch == '\n') {
216
            /* process line */
217
            if (q > line && q[-1] == '\r')
218
                q--;
219
            *q = '\0';
220
#ifdef DEBUG
221
            printf("header='%s'\n", line);
222
#endif
223
            err = process_line(s, line, s->line_count);
224
            if (err < 0)
225
                return err;
226
            if (err == 0)
227
                return 0;
228
            s->line_count++;
229
            q = line;
230
        } else {
231
            if ((q - line) < sizeof(line) - 1)
232
                *q++ = ch;
233
        }
234
    }
235
}
236
237
238 0c1a9eda Zdenek Kabelac
static int http_read(URLContext *h, uint8_t *buf, int size)
239 de6d9b64 Fabrice Bellard
{
240
    HTTPContext *s = h->priv_data;
241
    int size1, len;
242
243
    size1 = size;
244
    while (size > 0) {
245
        /* read bytes from input buffer first */
246
        len = s->buf_end - s->buf_ptr;
247
        if (len > 0) {
248
            if (len > size)
249
                len = size;
250
            memcpy(buf, s->buf_ptr, len);
251
            s->buf_ptr += len;
252
        } else {
253 0e2a2197 Fabrice Bellard
            len = url_read (s->hd, buf, size);
254 de6d9b64 Fabrice Bellard
            if (len < 0) {
255 0e2a2197 Fabrice Bellard
                return len;
256 de6d9b64 Fabrice Bellard
            } else if (len == 0) {
257
                break;
258
            }
259
        }
260
        size -= len;
261
        buf += len;
262
    }
263
    return size1 - size;
264
}
265
266
/* used only when posting data */
267 0c1a9eda Zdenek Kabelac
static int http_write(URLContext *h, uint8_t *buf, int size)
268 de6d9b64 Fabrice Bellard
{
269
    HTTPContext *s = h->priv_data;
270 0e2a2197 Fabrice Bellard
    return url_write(s->hd, buf, size);
271 de6d9b64 Fabrice Bellard
}
272
273
static int http_close(URLContext *h)
274
{
275
    HTTPContext *s = h->priv_data;
276 0e2a2197 Fabrice Bellard
    url_close(s->hd);
277
    av_free(s);
278 de6d9b64 Fabrice Bellard
    return 0;
279
}
280
281
URLProtocol http_protocol = {
282
    "http",
283
    http_open,
284
    http_read,
285
    http_write,
286
    NULL, /* seek */
287
    http_close,
288
};