Statistics
| Branch: | Revision:

ffmpeg / libav / http.c @ 9ddd71fc

History | View | Annotate | Download (6.82 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 <ctype.h>
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <netinet/in.h>
25
#ifndef __BEOS__
26
# include <arpa/inet.h>
27
#else
28
# include "barpainet.h"
29
#endif
30
#include <netdb.h>
31

    
32

    
33
/* XXX: POST protocol is not completly implemented because ffmpeg use
34
   only a subset of it */
35

    
36
//#define DEBUG
37

    
38
/* used for protocol handling */
39
#define BUFFER_SIZE 1024
40
#define URL_SIZE    4096
41

    
42
typedef struct {
43
    URLContext *hd;
44
    unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
45
    int line_count;
46
    int http_code;
47
    char location[URL_SIZE];
48
} HTTPContext;
49

    
50
static int http_connect(URLContext *h, const char *path, const char *hoststr);
51
static int http_write(URLContext *h, UINT8 *buf, int size);
52

    
53

    
54
/* return non zero if error */
55
static int http_open(URLContext *h, const char *uri, int flags)
56
{
57
    const char *path, *proxy_path;
58
    char hostname[1024], hoststr[1024];
59
    char path1[1024];
60
    char buf[1024];
61
    int port, use_proxy, err;
62
    HTTPContext *s;
63
    URLContext *hd = NULL;
64

    
65
    h->is_streamed = 1;
66

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

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

    
77
    /* fill the dest addr */
78
 redo:
79
    /* needed in any case to build the host string */
80
    url_split(NULL, 0, hostname, sizeof(hostname), &port, 
81
              path1, sizeof(path1), uri);
82
    if (port > 0) {
83
        snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port);
84
    } else {
85
        pstrcpy(hoststr, sizeof(hoststr), hostname);
86
    }
87

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

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

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

    
123
static int http_getc(HTTPContext *s)
124
{
125
    int len;
126
    if (s->buf_ptr >= s->buf_end) {
127
        len = url_read(s->hd, s->buffer, BUFFER_SIZE);
128
        if (len < 0) {
129
            return -EIO;
130
        } else if (len == 0) {
131
            return -1;
132
        } else {
133
            s->buf_ptr = s->buffer;
134
            s->buf_end = s->buffer + len;
135
        }
136
    }
137
    return *s->buf_ptr++;
138
}
139

    
140
static int process_line(HTTPContext *s, char *line, int line_count)
141
{
142
    char *tag, *p;
143
    
144
    /* end of header */
145
    if (line[0] == '\0')
146
        return 0;
147

    
148
    p = line;
149
    if (line_count == 0) {
150
        while (!isspace(*p) && *p != '\0')
151
            p++;
152
        while (isspace(*p))
153
            p++;
154
        s->http_code = strtol(p, NULL, 10);
155
#ifdef DEBUG
156
        printf("http_code=%d\n", s->http_code);
157
#endif
158
    } else {
159
        while (*p != '\0' && *p != ':')
160
            p++;
161
        if (*p != ':') 
162
            return 1;
163
        
164
        *p = '\0';
165
        tag = line;
166
        p++;
167
        while (isspace(*p))
168
            p++;
169
        if (!strcmp(tag, "Location")) {
170
            strcpy(s->location, p);
171
        }
172
    }
173
    return 1;
174
}
175

    
176
static int http_connect(URLContext *h, const char *path, const char *hoststr)
177
{
178
    HTTPContext *s = h->priv_data;
179
    int post, err, ch;
180
    char line[1024], *q;
181

    
182

    
183
    /* send http header */
184
    post = h->flags & URL_WRONLY;
185

    
186
    snprintf(s->buffer, sizeof(s->buffer),
187
             "%s %s HTTP/1.0\n"
188
             "User-Agent: FFmpeg %s\n"
189
             "Accept: */*\n"
190
             "Host: %s\n"
191
             "\n",
192
             post ? "POST" : "GET",
193
             path,
194
             FFMPEG_VERSION,
195
             hoststr);
196
    
197
    if (http_write(h, s->buffer, strlen(s->buffer)) < 0)
198
        return -EIO;
199
        
200
    /* init input buffer */
201
    s->buf_ptr = s->buffer;
202
    s->buf_end = s->buffer;
203
    s->line_count = 0;
204
    s->location[0] = '\0';
205
    if (post) {
206
        sleep(1);
207
        return 0;
208
    }
209
    
210
    /* wait for header */
211
    q = line;
212
    for(;;) {
213
        ch = http_getc(s);
214
        if (ch < 0)
215
            return -EIO;
216
        if (ch == '\n') {
217
            /* process line */
218
            if (q > line && q[-1] == '\r')
219
                q--;
220
            *q = '\0';
221
#ifdef DEBUG
222
            printf("header='%s'\n", line);
223
#endif
224
            err = process_line(s, line, s->line_count);
225
            if (err < 0)
226
                return err;
227
            if (err == 0)
228
                return 0;
229
            s->line_count++;
230
            q = line;
231
        } else {
232
            if ((q - line) < sizeof(line) - 1)
233
                *q++ = ch;
234
        }
235
    }
236
}
237

    
238

    
239
static int http_read(URLContext *h, UINT8 *buf, int size)
240
{
241
    HTTPContext *s = h->priv_data;
242
    int size1, len;
243

    
244
    size1 = size;
245
    while (size > 0) {
246
        /* read bytes from input buffer first */
247
        len = s->buf_end - s->buf_ptr;
248
        if (len > 0) {
249
            if (len > size)
250
                len = size;
251
            memcpy(buf, s->buf_ptr, len);
252
            s->buf_ptr += len;
253
        } else {
254
            len = url_read (s->hd, buf, size);
255
            if (len < 0) {
256
                return len;
257
            } else if (len == 0) {
258
                break;
259
            }
260
        }
261
        size -= len;
262
        buf += len;
263
    }
264
    return size1 - size;
265
}
266

    
267
/* used only when posting data */
268
static int http_write(URLContext *h, UINT8 *buf, int size)
269
{
270
    HTTPContext *s = h->priv_data;
271
    return url_write(s->hd, buf, size);
272
}
273

    
274
static int http_close(URLContext *h)
275
{
276
    HTTPContext *s = h->priv_data;
277
    url_close(s->hd);
278
    av_free(s);
279
    return 0;
280
}
281

    
282
URLProtocol http_protocol = {
283
    "http",
284
    http_open,
285
    http_read,
286
    http_write,
287
    NULL, /* seek */
288
    http_close,
289
};
290