http.c 35.7 KB
Newer Older
1
/*
2
 * HTTP protocol for avconv client
3
 * Copyright (c) 2000, 2001 Fabrice Bellard
4
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19 20
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */
21

22 23 24 25 26 27
#include "config.h"

#if CONFIG_ZLIB
#include <zlib.h>
#endif /* CONFIG_ZLIB */

28
#include "libavutil/avstring.h"
29 30
#include "libavutil/opt.h"

31
#include "avformat.h"
32 33
#include "http.h"
#include "httpauth.h"
34
#include "internal.h"
35
#include "network.h"
36
#include "os_support.h"
37
#include "url.h"
38

39
/* XXX: POST protocol is not completely implemented because avconv uses
40
 * only a subset of it. */
41

42 43
/* The IO buffer size is unrelated to the max URL size in itself, but needs
 * to be large enough to fit the full request headers (including long
44 45
 * path names). */
#define BUFFER_SIZE   MAX_URL_SIZE
46 47 48
#define MAX_REDIRECTS 8

typedef struct {
49
    const AVClass *class;
50 51 52 53
    URLContext *hd;
    unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
    int line_count;
    int http_code;
Luca Barbato's avatar
Luca Barbato committed
54 55
    /* Used if "Transfer-Encoding: chunked" otherwise -1. */
    int64_t chunksize;
56
    int64_t off, end_off, filesize;
57
    char *location;
58
    HTTPAuthState auth_state;
59
    HTTPAuthState proxy_auth_state;
60
    char *headers;
61
    char *mime_type;
62
    char *user_agent;
63
    char *content_type;
Luca Barbato's avatar
Luca Barbato committed
64 65 66
    /* Set if the server correctly handles Connection: close and will close
     * the connection after feeding us the content. */
    int willclose;
67
    int chunked_post;
Luca Barbato's avatar
Luca Barbato committed
68 69 70 71 72 73
    /* A flag which indicates if the end of chunked encoding has been sent. */
    int end_chunked_post;
    /* A flag which indicates we have finished to read POST reply. */
    int end_header;
    /* A flag which indicates if we use persistent connections. */
    int multiple_requests;
74 75
    uint8_t *post_data;
    int post_datalen;
76 77 78 79 80 81 82
    int icy;
    /* how much data was read since the last ICY metadata packet */
    int icy_data_read;
    /* after how many bytes of read data a new metadata packet will be found */
    int icy_metaint;
    char *icy_metadata_headers;
    char *icy_metadata_packet;
83 84 85 86
#if CONFIG_ZLIB
    int compressed;
    z_stream inflate_stream;
    uint8_t *inflate_buffer;
87
#endif /* CONFIG_ZLIB */
88
    AVDictionary *chained_options;
89
    int send_expect_100;
90
    char *method;
91 92
} HTTPContext;

93
#define OFFSET(x) offsetof(HTTPContext, x)
94 95
#define D AV_OPT_FLAG_DECODING_PARAM
#define E AV_OPT_FLAG_ENCODING_PARAM
96
#define DEFAULT_USER_AGENT "Lavf/" AV_STRINGIFY(LIBAVFORMAT_VERSION)
97

98
static const AVOption options[] = {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
    { "chunked_post", "use chunked transfer-encoding for posts", OFFSET(chunked_post), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, E },
    { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
    { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
    { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
    { "user-agent", "override User-Agent header, for compatibility with ffmpeg", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D },
    { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D | E },
    { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E },
    { "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY },
    { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, D },
    { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
    { "icy_metadata_packet", "return current ICY metadata packet", OFFSET(icy_metadata_packet), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_EXPORT },
    { "auth_type", "HTTP authentication type", OFFSET(auth_state.auth_type), AV_OPT_TYPE_INT, { .i64 = HTTP_AUTH_NONE }, HTTP_AUTH_NONE, HTTP_AUTH_BASIC, D | E, "auth_type"},
    { "none", "No auth method set, autodetect", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_NONE }, 0, 0, D | E, "auth_type"},
    { "basic", "HTTP basic authentication", 0, AV_OPT_TYPE_CONST, { .i64 = HTTP_AUTH_BASIC }, 0, 0, D | E, "auth_type"},
    { "send_expect_100", "Force sending an Expect: 100-continue header for POST", OFFSET(send_expect_100), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, E },
    { "location", "The actual location of the data received", OFFSET(location), AV_OPT_TYPE_STRING, { 0 }, 0, 0, D | E },
    { "offset", "initial byte offset", OFFSET(off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
    { "end_offset", "try to limit the request to bytes preceding this offset", OFFSET(end_off), AV_OPT_TYPE_INT64, { .i64 = 0 }, 0, INT64_MAX, D },
    { "method", "Override the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E },
    { NULL }
119
};
120

121 122 123
static int http_connect(URLContext *h, const char *path, const char *local_path,
                        const char *hoststr, const char *auth,
                        const char *proxyauth, int *new_location);
124

125 126
void ff_http_init_auth_state(URLContext *dest, const URLContext *src)
{
127 128 129 130 131
    memcpy(&((HTTPContext *)dest->priv_data)->auth_state,
           &((HTTPContext *)src->priv_data)->auth_state,
           sizeof(HTTPAuthState));
    memcpy(&((HTTPContext *)dest->priv_data)->proxy_auth_state,
           &((HTTPContext *)src->priv_data)->proxy_auth_state,
132
           sizeof(HTTPAuthState));
133 134
}

Luca Barbato's avatar
Luca Barbato committed
135
static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
136
{
137
    const char *path, *proxy_path, *lower_proto = "tcp", *local_path;
138
    char hostname[1024], hoststr[1024], proto[10];
139
    char auth[1024], proxyauth[1024] = "";
140 141
    char path1[MAX_URL_SIZE];
    char buf[1024], urlbuf[MAX_URL_SIZE];
Luca Barbato's avatar
Luca Barbato committed
142
    int port, use_proxy, err, location_changed = 0;
143 144
    HTTPContext *s = h->priv_data;

145 146
    av_url_split(proto, sizeof(proto), auth, sizeof(auth),
                 hostname, sizeof(hostname), &port,
Martin Storsjö's avatar
Martin Storsjö committed
147
                 path1, sizeof(path1), s->location);
148
    ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
149

150
    proxy_path = getenv("http_proxy");
151 152
    use_proxy  = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) &&
                 proxy_path != NULL && av_strstart(proxy_path, "http://", NULL);
153

154 155
    if (!strcmp(proto, "https")) {
        lower_proto = "tls";
156
        use_proxy   = 0;
157 158 159 160 161 162
        if (port < 0)
            port = 443;
    }
    if (port < 0)
        port = 80;

163 164 165 166 167
    if (path1[0] == '\0')
        path = "/";
    else
        path = path1;
    local_path = path;
168
    if (use_proxy) {
169 170 171 172 173 174 175
        /* Reassemble the request URL without auth string - we don't
         * want to leak the auth to the proxy. */
        ff_url_join(urlbuf, sizeof(urlbuf), proto, NULL, hostname, port, "%s",
                    path1);
        path = urlbuf;
        av_url_split(NULL, 0, proxyauth, sizeof(proxyauth),
                     hostname, sizeof(hostname), &port, NULL, 0, proxy_path);
176 177
    }

178
    ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL);
179

180
    if (!s->hd) {
181
        err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
182
                         &h->interrupt_callback, options);
183
        if (err < 0)
Luca Barbato's avatar
Luca Barbato committed
184
            return err;
185 186
    }

Luca Barbato's avatar
Luca Barbato committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
    err = http_connect(h, path, local_path, hoststr,
                       auth, proxyauth, &location_changed);
    if (err < 0)
        return err;

    return location_changed;
}

/* return non zero if error */
static int http_open_cnx(URLContext *h, AVDictionary **options)
{
    HTTPAuthType cur_auth_type, cur_proxy_auth_type;
    HTTPContext *s = h->priv_data;
    int location_changed, attempts = 0, redirects = 0;
redo:
    location_changed = http_open_cnx_internal(h, options);
    if (location_changed < 0)
204
        goto fail;
Luca Barbato's avatar
Luca Barbato committed
205

206
    attempts++;
Luca Barbato's avatar
Luca Barbato committed
207 208 209
    cur_auth_type       = s->auth_state.auth_type;
    cur_proxy_auth_type = s->auth_state.auth_type;

210
    if (s->http_code == 401) {
211 212
        if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
            s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
213 214
            ffurl_close(s->hd);
            s->hd = NULL;
215 216 217 218
            goto redo;
        } else
            goto fail;
    }
219
    if (s->http_code == 407) {
220 221
        if ((cur_proxy_auth_type == HTTP_AUTH_NONE || s->proxy_auth_state.stale) &&
            s->proxy_auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
222 223
            ffurl_close(s->hd);
            s->hd = NULL;
224 225 226 227
            goto redo;
        } else
            goto fail;
    }
228 229 230
    if ((s->http_code == 301 || s->http_code == 302 ||
         s->http_code == 303 || s->http_code == 307) &&
        location_changed == 1) {
231
        /* url moved, get next */
232 233
        ffurl_close(s->hd);
        s->hd = NULL;
234
        if (redirects++ >= MAX_REDIRECTS)
235
            return AVERROR(EIO);
236 237 238
        /* Restart the authentication process with the new target, which
         * might use a different auth mechanism. */
        memset(&s->auth_state, 0, sizeof(s->auth_state));
239
        attempts         = 0;
240 241 242 243
        location_changed = 0;
        goto redo;
    }
    return 0;
244 245

fail:
246 247
    if (s->hd)
        ffurl_close(s->hd);
248
    s->hd = NULL;
249
    return AVERROR(EIO);
250 251
}

252 253 254
int ff_http_do_new_request(URLContext *h, const char *uri)
{
    HTTPContext *s = h->priv_data;
255 256
    AVDictionary *options = NULL;
    int ret;
257

258
    s->off           = 0;
259
    s->icy_data_read = 0;
260 261 262 263
    av_free(s->location);
    s->location = av_strdup(uri);
    if (!s->location)
        return AVERROR(ENOMEM);
264

265 266 267 268
    av_dict_copy(&options, s->chained_options, 0);
    ret = http_open_cnx(h, &options);
    av_dict_free(&options);
    return ret;
269 270
}

271 272
static int http_open(URLContext *h, const char *uri, int flags,
                     AVDictionary **options)
273
{
274
    HTTPContext *s = h->priv_data;
275
    int ret;
276 277 278 279

    h->is_streamed = 1;

    s->filesize = -1;
280 281 282
    s->location = av_strdup(uri);
    if (!s->location)
        return AVERROR(ENOMEM);
283 284
    if (options)
        av_dict_copy(&s->chained_options, *options, 0);
285

286 287 288
    if (s->headers) {
        int len = strlen(s->headers);
        if (len < 2 || strcmp("\r\n", s->headers + len - 2))
289 290
            av_log(h, AV_LOG_WARNING,
                   "No trailing CRLF found in HTTP header.\n");
291 292
    }

293 294 295 296
    ret = http_open_cnx(h, options);
    if (ret < 0)
        av_dict_free(&s->chained_options);
    return ret;
297
}
298

299 300 301 302
static int http_getc(HTTPContext *s)
{
    int len;
    if (s->buf_ptr >= s->buf_end) {
303
        len = ffurl_read(s->hd, s->buffer, BUFFER_SIZE);
304
        if (len < 0) {
305
            return len;
306
        } else if (len == 0) {
307
            return AVERROR_EOF;
308 309 310 311 312 313 314 315
        } else {
            s->buf_ptr = s->buffer;
            s->buf_end = s->buffer + len;
        }
    }
    return *s->buf_ptr++;
}

316 317 318 319 320 321
static int http_get_line(HTTPContext *s, char *line, int line_size)
{
    int ch;
    char *q;

    q = line;
322
    for (;;) {
323 324
        ch = http_getc(s);
        if (ch < 0)
325
            return ch;
326 327 328 329 330 331 332 333 334 335 336 337 338 339
        if (ch == '\n') {
            /* process line */
            if (q > line && q[-1] == '\r')
                q--;
            *q = '\0';

            return 0;
        } else {
            if ((q - line) < line_size - 1)
                *q++ = ch;
        }
    }
}

Luca Barbato's avatar
Luca Barbato committed
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
static int check_http_code(URLContext *h, int http_code, const char *end)
{
    HTTPContext *s = h->priv_data;
    /* error codes are 4xx and 5xx, but regard 401 as a success, so we
     * don't abort until all headers have been parsed. */
    if (http_code >= 400 && http_code < 600 &&
        (http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) &&
        (http_code != 407 || s->proxy_auth_state.auth_type != HTTP_AUTH_NONE)) {
        end += strspn(end, SPACE_CHARS);
        av_log(h, AV_LOG_WARNING, "HTTP error %d %s\n", http_code, end);
        return AVERROR(EIO);
    }
    return 0;
}

static int parse_location(HTTPContext *s, const char *p)
{
    char redirected_location[MAX_URL_SIZE], *new_loc;
    ff_make_absolute_url(redirected_location, sizeof(redirected_location),
                         s->location, p);
    new_loc = av_strdup(redirected_location);
    if (!new_loc)
        return AVERROR(ENOMEM);
    av_free(s->location);
    s->location = new_loc;
    return 0;
}

/* "bytes $from-$to/$document_size" */
369
static void parse_content_range(URLContext *h, const char *p)
Luca Barbato's avatar
Luca Barbato committed
370 371 372 373 374
{
    HTTPContext *s = h->priv_data;
    const char *slash;

    if (!strncmp(p, "bytes ", 6)) {
375
        p     += 6;
Luca Barbato's avatar
Luca Barbato committed
376 377
        s->off = strtoll(p, NULL, 10);
        if ((slash = strchr(p, '/')) && strlen(slash) > 0)
378
            s->filesize = strtoll(slash + 1, NULL, 10);
Luca Barbato's avatar
Luca Barbato committed
379 380 381 382
    }
    h->is_streamed = 0; /* we _can_ in fact seek */
}

383
static int parse_content_encoding(URLContext *h, const char *p)
Luca Barbato's avatar
Luca Barbato committed
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405
{
    HTTPContext *s = h->priv_data;

    if (!av_strncasecmp(p, "gzip", 4) ||
        !av_strncasecmp(p, "deflate", 7)) {
#if CONFIG_ZLIB
        s->compressed = 1;
        inflateEnd(&s->inflate_stream);
        if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
            av_log(h, AV_LOG_WARNING, "Error during zlib initialisation: %s\n",
                   s->inflate_stream.msg);
            return AVERROR(ENOSYS);
        }
        if (zlibCompileFlags() & (1 << 17)) {
            av_log(h, AV_LOG_WARNING,
                   "Your zlib was compiled without gzip support.\n");
            return AVERROR(ENOSYS);
        }
#else
        av_log(h, AV_LOG_WARNING,
               "Compressed (%s) content, need zlib with gzip support\n", p);
        return AVERROR(ENOSYS);
406
#endif /* CONFIG_ZLIB */
Luca Barbato's avatar
Luca Barbato committed
407 408 409 410 411 412 413 414 415 416
    } else if (!av_strncasecmp(p, "identity", 8)) {
        // The normal, no-encoding case (although servers shouldn't include
        // the header at all if this is the case).
    } else {
        av_log(h, AV_LOG_WARNING, "Unknown content coding: %s\n", p);
        return AVERROR(ENOSYS);
    }
    return 0;
}

417 418 419 420
// Concat all Icy- header lines
static int parse_icy(HTTPContext *s, const char *tag, const char *p)
{
    int len = 4 + strlen(p) + strlen(tag);
421
    int is_first = !s->icy_metadata_headers;
422 423 424 425 426 427 428 429
    int ret;

    if (s->icy_metadata_headers)
        len += strlen(s->icy_metadata_headers);

    if ((ret = av_reallocp(&s->icy_metadata_headers, len)) < 0)
        return ret;

430 431 432
    if (is_first)
        *s->icy_metadata_headers = '\0';

433 434 435 436 437
    av_strlcatf(s->icy_metadata_headers, len, "%s: %s\n", tag, p);

    return 0;
}

438 439 440 441
static int process_line(URLContext *h, char *line, int line_count,
                        int *new_location)
{
    HTTPContext *s = h->priv_data;
442
    char *tag, *p, *end;
Luca Barbato's avatar
Luca Barbato committed
443
    int ret;
444 445

    /* end of header */
446 447
    if (line[0] == '\0') {
        s->end_header = 1;
448
        return 0;
449
    }
450 451 452

    p = line;
    if (line_count == 0) {
453
        while (!av_isspace(*p) && *p != '\0')
454
            p++;
455
        while (av_isspace(*p))
456
            p++;
457
        s->http_code = strtol(p, &end, 10);
458

Luca Barbato's avatar
Luca Barbato committed
459
        av_dlog(NULL, "http_code=%d\n", s->http_code);
460

Luca Barbato's avatar
Luca Barbato committed
461 462
        if ((ret = check_http_code(h, s->http_code, end)) < 0)
            return ret;
463 464 465 466 467 468
    } else {
        while (*p != '\0' && *p != ':')
            p++;
        if (*p != ':')
            return 1;

469
        *p  = '\0';
470 471
        tag = line;
        p++;
472
        while (av_isspace(*p))
473
            p++;
474
        if (!av_strcasecmp(tag, "Location")) {
Luca Barbato's avatar
Luca Barbato committed
475 476
            if ((ret = parse_location(s, p)) < 0)
                return ret;
477
            *new_location = 1;
478
        } else if (!av_strcasecmp(tag, "Content-Length") && s->filesize == -1) {
479
            s->filesize = strtoll(p, NULL, 10);
480
        } else if (!av_strcasecmp(tag, "Content-Range")) {
Luca Barbato's avatar
Luca Barbato committed
481
            parse_content_range(h, p);
482 483
        } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
                   !strncmp(p, "bytes", 5)) {
484
            h->is_streamed = 0;
485 486
        } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
                   !av_strncasecmp(p, "chunked", 7)) {
487
            s->filesize  = -1;
488
            s->chunksize = 0;
489
        } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
490
            ff_http_auth_handle_header(&s->auth_state, tag, p);
491
        } else if (!av_strcasecmp(tag, "Authentication-Info")) {
492
            ff_http_auth_handle_header(&s->auth_state, tag, p);
493
        } else if (!av_strcasecmp(tag, "Proxy-Authenticate")) {
494
            ff_http_auth_handle_header(&s->proxy_auth_state, tag, p);
495
        } else if (!av_strcasecmp(tag, "Connection")) {
496 497
            if (!strcmp(p, "close"))
                s->willclose = 1;
498
        } else if (!av_strcasecmp(tag, "Content-Type")) {
499 500
            av_free(s->mime_type);
            s->mime_type = av_strdup(p);
501
        } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
502 503 504 505
            s->icy_metaint = strtoll(p, NULL, 10);
        } else if (!av_strncasecmp(tag, "Icy-", 4)) {
            if ((ret = parse_icy(s, tag, p)) < 0)
                return ret;
506
        } else if (!av_strcasecmp(tag, "Content-Encoding")) {
Luca Barbato's avatar
Luca Barbato committed
507 508
            if ((ret = parse_content_encoding(h, p)) < 0)
                return ret;
509 510 511 512 513
        }
    }
    return 1;
}

514 515 516
static inline int has_header(const char *str, const char *header)
{
    /* header + 2 to skip over CRLF prefix. (make sure you have one!) */
517 518
    if (!str)
        return 0;
519 520 521
    return av_stristart(str, header + 2, NULL) || av_stristr(str, header);
}

522 523 524
static int http_read_header(URLContext *h, int *new_location)
{
    HTTPContext *s = h->priv_data;
525
    char line[MAX_URL_SIZE];
526 527
    int err = 0;

528 529
    s->chunksize = -1;

530
    for (;;) {
531 532
        if ((err = http_get_line(s, line, sizeof(line))) < 0)
            return err;
533 534 535 536 537 538 539 540 541 542 543 544 545 546

        av_dlog(NULL, "header='%s'\n", line);

        err = process_line(h, line, s->line_count, new_location);
        if (err < 0)
            return err;
        if (err == 0)
            break;
        s->line_count++;
    }

    return err;
}

547 548 549
static int http_connect(URLContext *h, const char *path, const char *local_path,
                        const char *hoststr, const char *auth,
                        const char *proxyauth, int *new_location)
550 551
{
    HTTPContext *s = h->priv_data;
552
    int post, err;
553
    char headers[HTTP_HEADERS_SIZE] = "";
554
    char *authstr = NULL, *proxyauthstr = NULL;
555
    int64_t off = s->off;
556
    int len = 0;
557
    const char *method;
558
    int send_expect_100 = 0;
559 560

    /* send http header */
561
    post = h->flags & AVIO_FLAG_WRITE;
562 563 564 565

    if (s->post_data) {
        /* force POST method and disable chunked encoding when
         * custom HTTP post data is set */
566
        post            = 1;
567 568 569
        s->chunked_post = 0;
    }

570 571 572 573 574
    if (s->method)
        method = s->method;
    else
        method = post ? "POST" : "GET";

575 576
    authstr      = ff_http_auth_create_response(&s->auth_state, auth,
                                                local_path, method);
577 578
    proxyauthstr = ff_http_auth_create_response(&s->proxy_auth_state, proxyauth,
                                                local_path, method);
579 580 581 582 583 584
    if (post && !s->post_data) {
        send_expect_100 = s->send_expect_100;
        /* The user has supplied authentication but we don't know the auth type,
         * send Expect: 100-continue to get the 401 response including the
         * WWW-Authenticate header, or an 100 continue if no auth actually
         * is needed. */
585 586
        if (auth && *auth &&
            s->auth_state.auth_type == HTTP_AUTH_NONE &&
587 588 589
            s->http_code != 401)
            send_expect_100 = 1;
    }
590 591 592

    /* set default headers if needed */
    if (!has_header(s->headers, "\r\nUser-Agent: "))
593 594
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "User-Agent: %s\r\n", s->user_agent);
595 596 597
    if (!has_header(s->headers, "\r\nAccept: "))
        len += av_strlcpy(headers + len, "Accept: */*\r\n",
                          sizeof(headers) - len);
598 599 600 601
    // Note: we send this on purpose even when s->off is 0 when we're probing,
    // since it allows us to detect more reliably if a (non-conforming)
    // server supports seeking by analysing the reply headers.
    if (!has_header(s->headers, "\r\nRange: ") && !post) {
602
        len += av_strlcatf(headers + len, sizeof(headers) - len,
603 604 605 606 607 608 609
                           "Range: bytes=%"PRId64"-", s->off);
        if (s->end_off)
            len += av_strlcatf(headers + len, sizeof(headers) - len,
                               "%"PRId64, s->end_off - 1);
        len += av_strlcpy(headers + len, "\r\n",
                          sizeof(headers) - len);
    }
610 611 612
    if (send_expect_100 && !has_header(s->headers, "\r\nExpect: "))
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "Expect: 100-continue\r\n");
613 614

    if (!has_header(s->headers, "\r\nConnection: ")) {
615
        if (s->multiple_requests)
616 617
            len += av_strlcpy(headers + len, "Connection: keep-alive\r\n",
                              sizeof(headers) - len);
618
        else
619 620 621 622
            len += av_strlcpy(headers + len, "Connection: close\r\n",
                              sizeof(headers) - len);
    }

623 624 625
    if (!has_header(s->headers, "\r\nHost: "))
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "Host: %s\r\n", hoststr);
626 627 628
    if (!has_header(s->headers, "\r\nContent-Length: ") && s->post_data)
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "Content-Length: %d\r\n", s->post_datalen);
629 630 631 632

    if (!has_header(s->headers, "\r\nContent-Type: ") && s->content_type)
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "Content-Type: %s\r\n", s->content_type);
633
    if (!has_header(s->headers, "\r\nIcy-MetaData: ") && s->icy)
634 635
        len += av_strlcatf(headers + len, sizeof(headers) - len,
                           "Icy-MetaData: %d\r\n", 1);
636 637

    /* now add in custom headers */
638 639
    if (s->headers)
        av_strlcpy(headers + len, s->headers, sizeof(headers) - len);
640

641 642
    snprintf(s->buffer, sizeof(s->buffer),
             "%s %s HTTP/1.1\r\n"
643
             "%s"
644
             "%s"
645
             "%s"
646
             "%s%s"
647
             "\r\n",
648
             method,
649
             path,
650
             post && s->chunked_post ? "Transfer-Encoding: chunked\r\n" : "",
651
             headers,
652 653
             authstr ? authstr : "",
             proxyauthstr ? "Proxy-" : "", proxyauthstr ? proxyauthstr : "");
654

655
    av_freep(&authstr);
656
    av_freep(&proxyauthstr);
657 658
    if ((err = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
        return err;
659

660 661 662 663
    if (s->post_data)
        if ((err = ffurl_write(s->hd, s->post_data, s->post_datalen)) < 0)
            return err;

664
    /* init input buffer */
665 666 667 668 669 670 671
    s->buf_ptr          = s->buffer;
    s->buf_end          = s->buffer;
    s->line_count       = 0;
    s->off              = 0;
    s->icy_data_read    = 0;
    s->filesize         = -1;
    s->willclose        = 0;
672
    s->end_chunked_post = 0;
673
    s->end_header       = 0;
674
    if (post && !s->post_data && !send_expect_100) {
675 676 677 678
        /* Pretend that it did work. We didn't read any header yet, since
         * we've still to send the POST data, but the code calling this
         * function will check http_code after we return. */
        s->http_code = 200;
679 680 681 682
        return 0;
    }

    /* wait for header */
683 684 685
    err = http_read_header(h, new_location);
    if (err < 0)
        return err;
686 687 688 689

    return (off == s->off) ? 0 : -1;
}

690
static int http_buf_read(URLContext *h, uint8_t *buf, int size)
691 692 693
{
    HTTPContext *s = h->priv_data;
    int len;
694 695 696 697 698 699 700 701
    /* read bytes from input buffer first */
    len = s->buf_end - s->buf_ptr;
    if (len > 0) {
        if (len > size)
            len = size;
        memcpy(buf, s->buf_ptr, len);
        s->buf_ptr += len;
    } else {
702 703
        if ((!s->willclose || s->chunksize < 0) &&
            s->filesize >= 0 && s->off >= s->filesize)
704 705 706 707 708 709 710 711 712 713 714
            return AVERROR_EOF;
        len = ffurl_read(s->hd, buf, size);
    }
    if (len > 0) {
        s->off += len;
        if (s->chunksize > 0)
            s->chunksize -= len;
    }
    return len;
}

715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740
#if CONFIG_ZLIB
#define DECOMPRESS_BUF_SIZE (256 * 1024)
static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
{
    HTTPContext *s = h->priv_data;
    int ret;

    if (!s->inflate_buffer) {
        s->inflate_buffer = av_malloc(DECOMPRESS_BUF_SIZE);
        if (!s->inflate_buffer)
            return AVERROR(ENOMEM);
    }

    if (s->inflate_stream.avail_in == 0) {
        int read = http_buf_read(h, s->inflate_buffer, DECOMPRESS_BUF_SIZE);
        if (read <= 0)
            return read;
        s->inflate_stream.next_in  = s->inflate_buffer;
        s->inflate_stream.avail_in = read;
    }

    s->inflate_stream.avail_out = size;
    s->inflate_stream.next_out  = buf;

    ret = inflate(&s->inflate_stream, Z_SYNC_FLUSH);
    if (ret != Z_OK && ret != Z_STREAM_END)
741 742
        av_log(h, AV_LOG_WARNING, "inflate return value: %d, %s\n",
               ret, s->inflate_stream.msg);
743 744 745

    return size - s->inflate_stream.avail_out;
}
746
#endif /* CONFIG_ZLIB */
747

748
static int http_read_stream(URLContext *h, uint8_t *buf, int size)
749 750
{
    HTTPContext *s = h->priv_data;
751 752
    int err, new_location;

753 754 755
    if (!s->hd)
        return AVERROR_EOF;

756 757 758 759
    if (s->end_chunked_post && !s->end_header) {
        err = http_read_header(h, &new_location);
        if (err < 0)
            return err;
760
    }
761

762 763 764 765
    if (s->chunksize >= 0) {
        if (!s->chunksize) {
            char line[32];

766
            for (;;) {
767
                do {
768 769
                    if ((err = http_get_line(s, line, sizeof(line))) < 0)
                        return err;
770 771 772 773
                } while (!*line);    /* skip CR LF from last chunk */

                s->chunksize = strtoll(line, NULL, 16);

774 775
                av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n",
                        s->chunksize);
776 777 778 779 780 781 782 783

                if (!s->chunksize)
                    return 0;
                break;
            }
        }
        size = FFMIN(size, s->chunksize);
    }
784 785 786
#if CONFIG_ZLIB
    if (s->compressed)
        return http_buf_read_compressed(h, buf, size);
787
#endif /* CONFIG_ZLIB */
788
    return http_buf_read(h, buf, size);
789 790
}

791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
{
    int pos = 0;
    while (pos < size) {
        int len = http_read_stream(h, buf + pos, size - pos);
        if (len < 0)
            return len;
        pos += len;
    }
    return pos;
}

static int store_icy(URLContext *h, int size)
{
    HTTPContext *s = h->priv_data;
    /* until next metadata packet */
    int remaining = s->icy_metaint - s->icy_data_read;

    if (remaining < 0)
        return AVERROR_INVALIDDATA;

    if (!remaining) {
813 814 815 816
        /* The metadata packet is variable sized. It has a 1 byte header
         * which sets the length of the packet (divided by 16). If it's 0,
         * the metadata doesn't change. After the packet, icy_metaint bytes
         * of normal data follows. */
817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
        uint8_t ch;
        int len = http_read_stream_all(h, &ch, 1);
        if (len < 0)
            return len;
        if (ch > 0) {
            char data[255 * 16 + 1];
            int ret;
            len = ch * 16;
            ret = http_read_stream_all(h, data, len);
            if (ret < 0)
                return ret;
            data[len + 1] = 0;
            if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
                return ret;
        }
        s->icy_data_read = 0;
833
        remaining        = s->icy_metaint;
834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854
    }

    return FFMIN(size, remaining);
}

static int http_read(URLContext *h, uint8_t *buf, int size)
{
    HTTPContext *s = h->priv_data;

    if (s->icy_metaint > 0) {
        size = store_icy(h, size);
        if (size < 0)
            return size;
    }

    size = http_read_stream(h, buf, size);
    if (size > 0)
        s->icy_data_read += size;
    return size;
}

855
/* used only when posting data */
856
static int http_write(URLContext *h, const uint8_t *buf, int size)
857
{
858
    char temp[11] = "";  /* 32-bit hex + CRLF + nul */
859 860
    int ret;
    char crlf[] = "\r\n";
861
    HTTPContext *s = h->priv_data;
862

863
    if (!s->chunked_post) {
Martin Storsjö's avatar
Martin Storsjö committed
864
        /* non-chunked data is sent without any special encoding */
865
        return ffurl_write(s->hd, buf, size);
866 867 868 869 870 871
    }

    /* silently ignore zero-size data since chunk encoding that would
     * signal EOF */
    if (size > 0) {
        /* upload data using chunked encoding */
Martin Storsjö's avatar
Martin Storsjö committed
872
        snprintf(temp, sizeof(temp), "%x\r\n", size);
873

874
        if ((ret = ffurl_write(s->hd, temp, strlen(temp))) < 0 ||
875
            (ret = ffurl_write(s->hd, buf, size)) < 0          ||
876
            (ret = ffurl_write(s->hd, crlf, sizeof(crlf) - 1)) < 0)
877 878 879
            return ret;
    }
    return size;
880 881
}

882
static int http_shutdown(URLContext *h, int flags)
883
{
884 885
    int ret = 0;
    char footer[] = "0\r\n\r\n";
886
    HTTPContext *s = h->priv_data;
887 888

    /* signal end of chunked encoding if used */
889
    if ((flags & AVIO_FLAG_WRITE) && s->chunked_post) {
890
        ret = ffurl_write(s->hd, footer, sizeof(footer) - 1);
891
        ret = ret > 0 ? 0 : ret;
892 893 894 895 896 897 898 899 900 901 902
        s->end_chunked_post = 1;
    }

    return ret;
}

static int http_close(URLContext *h)
{
    int ret = 0;
    HTTPContext *s = h->priv_data;

903 904 905
#if CONFIG_ZLIB
    inflateEnd(&s->inflate_stream);
    av_freep(&s->inflate_buffer);
906
#endif /* CONFIG_ZLIB */
907

908
    if (!s->end_chunked_post)
909 910
        /* Close the write direction by sending the end of chunked encoding. */
        ret = http_shutdown(h, h->flags);
911

912
    if (s->hd)
913
        ffurl_close(s->hd);
914
    av_dict_free(&s->chained_options);
915
    return ret;
916 917
}

918
static int64_t http_seek(URLContext *h, int64_t off, int whence)
919 920 921
{
    HTTPContext *s = h->priv_data;
    URLContext *old_hd = s->hd;
922
    int64_t old_off = s->off;
923
    uint8_t old_buf[BUFFER_SIZE];
924
    int old_buf_size, ret;
925
    AVDictionary *options = NULL;
926 927 928

    if (whence == AVSEEK_SIZE)
        return s->filesize;
929 930 931
    else if ((whence == SEEK_CUR && off == 0) ||
             (whence == SEEK_SET && off == s->off))
        return s->off;
932
    else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed)
933
        return AVERROR(ENOSYS);
934 935

    /* we save the old context in case the seek fails */
936 937
    old_buf_size = s->buf_end - s->buf_ptr;
    memcpy(old_buf, s->buf_ptr, old_buf_size);
938 939 940 941 942 943 944 945
    s->hd = NULL;
    if (whence == SEEK_CUR)
        off += s->off;
    else if (whence == SEEK_END)
        off += s->filesize;
    s->off = off;

    /* if it fails, continue on old connection */
946
    av_dict_copy(&options, s->chained_options, 0);
947
    if ((ret = http_open_cnx(h, &options)) < 0) {
948
        av_dict_free(&options);
949 950 951
        memcpy(s->buffer, old_buf, old_buf_size);
        s->buf_ptr = s->buffer;
        s->buf_end = s->buffer + old_buf_size;
952 953
        s->hd      = old_hd;
        s->off     = old_off;
954
        return ret;
955
    }
956
    av_dict_free(&options);
957
    ffurl_close(old_hd);
958 959 960
    return off;
}

961
static int http_get_file_handle(URLContext *h)
962 963
{
    HTTPContext *s = h->priv_data;
964
    return ffurl_get_file_handle(s->hd);
965 966
}

967 968 969 970 971 972
#define HTTP_CLASS(flavor)                          \
static const AVClass flavor ## _context_class = {   \
    .class_name = # flavor,                         \
    .item_name  = av_default_item_name,             \
    .option     = options,                          \
    .version    = LIBAVUTIL_VERSION_INT,            \
973 974
}

975
#if CONFIG_HTTP_PROTOCOL
976 977
HTTP_CLASS(http);

978
URLProtocol ff_http_protocol = {
979
    .name                = "http",
980
    .url_open2           = http_open,
981 982 983 984
    .url_read            = http_read,
    .url_write           = http_write,
    .url_seek            = http_seek,
    .url_close           = http_close,
985
    .url_get_file_handle = http_get_file_handle,
986
    .url_shutdown        = http_shutdown,
987
    .priv_data_size      = sizeof(HTTPContext),
988
    .priv_data_class     = &http_context_class,
989
    .flags               = URL_PROTOCOL_FLAG_NETWORK,
990
};
991 992
#endif /* CONFIG_HTTP_PROTOCOL */

993
#if CONFIG_HTTPS_PROTOCOL
994 995
HTTP_CLASS(https);

996 997
URLProtocol ff_https_protocol = {
    .name                = "https",
998
    .url_open2           = http_open,
999 1000 1001 1002 1003
    .url_read            = http_read,
    .url_write           = http_write,
    .url_seek            = http_seek,
    .url_close           = http_close,
    .url_get_file_handle = http_get_file_handle,
1004
    .url_shutdown        = http_shutdown,
1005
    .priv_data_size      = sizeof(HTTPContext),
1006
    .priv_data_class     = &https_context_class,
1007
    .flags               = URL_PROTOCOL_FLAG_NETWORK,
1008
};
1009
#endif /* CONFIG_HTTPS_PROTOCOL */
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024

#if CONFIG_HTTPPROXY_PROTOCOL
static int http_proxy_close(URLContext *h)
{
    HTTPContext *s = h->priv_data;
    if (s->hd)
        ffurl_close(s->hd);
    return 0;
}

static int http_proxy_open(URLContext *h, const char *uri, int flags)
{
    HTTPContext *s = h->priv_data;
    char hostname[1024], hoststr[1024];
    char auth[1024], pathbuf[1024], *path;
1025
    char lower_url[100];
1026
    int port, ret = 0, attempts = 0;
1027 1028
    HTTPAuthType cur_auth_type;
    char *authstr;
1029
    int new_loc;
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063

    h->is_streamed = 1;

    av_url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port,
                 pathbuf, sizeof(pathbuf), uri);
    ff_url_join(hoststr, sizeof(hoststr), NULL, NULL, hostname, port, NULL);
    path = pathbuf;
    if (*path == '/')
        path++;

    ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port,
                NULL);
redo:
    ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
                     &h->interrupt_callback, NULL);
    if (ret < 0)
        return ret;

    authstr = ff_http_auth_create_response(&s->proxy_auth_state, auth,
                                           path, "CONNECT");
    snprintf(s->buffer, sizeof(s->buffer),
             "CONNECT %s HTTP/1.1\r\n"
             "Host: %s\r\n"
             "Connection: close\r\n"
             "%s%s"
             "\r\n",
             path,
             hoststr,
             authstr ? "Proxy-" : "", authstr ? authstr : "");
    av_freep(&authstr);

    if ((ret = ffurl_write(s->hd, s->buffer, strlen(s->buffer))) < 0)
        goto fail;