Statistics
| Branch: | Revision:

ffmpeg / libavformat / http.c @ 20f269dc

History | View | Annotate | Download (6.81 KB)

1
/*
2
 * HTTP protocol for ffmpeg client
3
 * Copyright (c) 2000, 2001 Fabrice Bellard.
4
 *
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.
9
 *
10
 * This library 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 GNU
13
 * Lesser General Public License for more details.
14
 *
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
18
 */
19
#include "avformat.h"
20
#include <unistd.h>
21
#include <sys/types.h>
22
#include <sys/socket.h>
23
#include <netinet/in.h>
24
#ifndef __BEOS__
25
# include <arpa/inet.h>
26
#else
27
# include "barpainet.h"
28
#endif
29
#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
    URLContext *hd;
43
    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
static int http_connect(URLContext *h, const char *path, const char *hoststr);
50
static int http_write(URLContext *h, uint8_t *buf, int size);
51

    
52

    
53
/* return non zero if error */
54
static int http_open(URLContext *h, const char *uri, int flags)
55
{
56
    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
    HTTPContext *s;
62
    URLContext *hd = NULL;
63

    
64
    h->is_streamed = 1;
65

    
66
    s = av_malloc(sizeof(HTTPContext));
67
    if (!s) {
68
        return -ENOMEM;
69
    }
70
    h->priv_data = s;
71

    
72
    proxy_path = getenv("http_proxy");
73
    use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && 
74
        strstart(proxy_path, "http://", NULL);
75

    
76
    /* fill the dest addr */
77
 redo:
78
    /* 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
    } else {
84
        pstrcpy(hoststr, sizeof(hoststr), hostname);
85
    }
86

    
87
    if (use_proxy) {
88
        url_split(NULL, 0, hostname, sizeof(hostname), &port, 
89
                  NULL, 0, proxy_path);
90
        path = uri;
91
    } else {
92
        if (path1[0] == '\0')
93
            path = "/";
94
        else
95
            path = path1;
96
    }
97
    if (port < 0)
98
        port = 80;
99

    
100
    snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port);
101
    err = url_open(&hd, buf, URL_RDWR);
102
    if (err < 0)
103
        goto fail;
104

    
105
    s->hd = hd;
106
    if (http_connect(h, path, hoststr) < 0)
107
        goto fail;
108
    if (s->http_code == 303 && s->location[0] != '\0') {
109
        /* url moved, get next */
110
        uri = s->location;
111
        url_close(hd);
112
        goto redo;
113
    }
114
    return 0;
115
 fail:
116
    if (hd)
117
        url_close(hd);
118
    av_free(s);
119
    return -EIO;
120
}
121

    
122
static int http_getc(HTTPContext *s)
123
{
124
    int len;
125
    if (s->buf_ptr >= s->buf_end) {
126
        len = url_read(s->hd, s->buffer, BUFFER_SIZE);
127
        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
static int http_connect(URLContext *h, const char *path, const char *hoststr)
176
{
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
             "Host: %s\n"
190
             "\n",
191
             post ? "POST" : "GET",
192
             path,
193
             LIBAVFORMAT_VERSION,
194
             hoststr);
195
    
196
    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
    if (post) {
205
        sleep(1);
206
        return 0;
207
    }
208
    
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
static int http_read(URLContext *h, uint8_t *buf, int size)
239
{
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
            len = url_read (s->hd, buf, size);
254
            if (len < 0) {
255
                return len;
256
            } 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
static int http_write(URLContext *h, uint8_t *buf, int size)
268
{
269
    HTTPContext *s = h->priv_data;
270
    return url_write(s->hd, buf, size);
271
}
272

    
273
static int http_close(URLContext *h)
274
{
275
    HTTPContext *s = h->priv_data;
276
    url_close(s->hd);
277
    av_free(s);
278
    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
};
289