avformat: Free the internal codec context at the end
[ffmpeg.git] / libavformat / http.c
index b2e07b4..00cf295 100644 (file)
@@ -45,7 +45,7 @@
 #define BUFFER_SIZE   MAX_URL_SIZE
 #define MAX_REDIRECTS 8
 
-typedef struct {
+typedef struct HTTPContext {
     const AVClass *class;
     URLContext *hd;
     unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end;
@@ -80,6 +80,7 @@ typedef struct {
     int icy_metaint;
     char *icy_metadata_headers;
     char *icy_metadata_packet;
+    AVDictionary *metadata;
 #if CONFIG_ZLIB
     int compressed;
     z_stream inflate_stream;
@@ -104,9 +105,10 @@ static const AVOption options[] = {
     { "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", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_INT, { .i64 = 1 }, 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 },
+    { "metadata", "metadata read from the bitstream", OFFSET(metadata), AV_OPT_TYPE_DICT, {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"},
@@ -149,7 +151,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
 
     proxy_path = getenv("http_proxy");
     use_proxy  = !ff_http_match_no_proxy(getenv("no_proxy"), hostname) &&
-                 proxy_path != NULL && av_strstart(proxy_path, "http://", NULL);
+                 proxy_path && av_strstart(proxy_path, "http://", NULL);
 
     if (!strcmp(proto, "https")) {
         lower_proto = "tls";
@@ -179,7 +181,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options)
 
     if (!s->hd) {
         err = ffurl_open(&s->hd, buf, AVIO_FLAG_READ_WRITE,
-                         &h->interrupt_callback, options);
+                         &h->interrupt_callback, options, h->protocols, h);
         if (err < 0)
             return err;
     }
@@ -199,14 +201,14 @@ static int http_open_cnx(URLContext *h, AVDictionary **options)
     HTTPContext *s = h->priv_data;
     int location_changed, attempts = 0, redirects = 0;
 redo:
+    cur_auth_type       = s->auth_state.auth_type;
+    cur_proxy_auth_type = s->auth_state.auth_type;
+
     location_changed = http_open_cnx_internal(h, options);
     if (location_changed < 0)
         goto fail;
 
     attempts++;
-    cur_auth_type       = s->auth_state.auth_type;
-    cur_proxy_auth_type = s->auth_state.auth_type;
-
     if (s->http_code == 401) {
         if ((cur_auth_type == HTTP_AUTH_NONE || s->auth_state.stale) &&
             s->auth_state.auth_type != HTTP_AUTH_NONE && attempts < 4) {
@@ -285,9 +287,16 @@ static int http_open(URLContext *h, const char *uri, int flags,
 
     if (s->headers) {
         int len = strlen(s->headers);
-        if (len < 2 || strcmp("\r\n", s->headers + len - 2))
+        if (len < 2 || strcmp("\r\n", s->headers + len - 2)) {
             av_log(h, AV_LOG_WARNING,
                    "No trailing CRLF found in HTTP header.\n");
+            ret = av_reallocp(&s->headers, len + 3);
+            if (ret < 0)
+                return ret;
+            s->headers[len]     = '\r';
+            s->headers[len + 1] = '\n';
+            s->headers[len + 2] = '\0';
+        }
     }
 
     ret = http_open_cnx(h, options);
@@ -382,11 +391,11 @@ static void parse_content_range(URLContext *h, const char *p)
 
 static int parse_content_encoding(URLContext *h, const char *p)
 {
-    HTTPContext *s = h->priv_data;
-
     if (!av_strncasecmp(p, "gzip", 4) ||
         !av_strncasecmp(p, "deflate", 7)) {
 #if CONFIG_ZLIB
+        HTTPContext *s = h->priv_data;
+
         s->compressed = 1;
         inflateEnd(&s->inflate_stream);
         if (inflateInit2(&s->inflate_stream, 32 + 15) != Z_OK) {
@@ -421,6 +430,8 @@ static int parse_icy(HTTPContext *s, const char *tag, const char *p)
     int is_first = !s->icy_metadata_headers;
     int ret;
 
+    av_dict_set(&s->metadata, tag, p, 0);
+
     if (s->icy_metadata_headers)
         len += strlen(s->icy_metadata_headers);
 
@@ -456,7 +467,7 @@ static int process_line(URLContext *h, char *line, int line_count,
             p++;
         s->http_code = strtol(p, &end, 10);
 
-        av_dlog(NULL, "http_code=%d\n", s->http_code);
+        av_log(NULL, AV_LOG_TRACE, "http_code=%d\n", s->http_code);
 
         if ((ret = check_http_code(h, s->http_code, end)) < 0)
             return ret;
@@ -531,7 +542,7 @@ static int http_read_header(URLContext *h, int *new_location)
         if ((err = http_get_line(s, line, sizeof(line))) < 0)
             return err;
 
-        av_dlog(NULL, "header='%s'\n", line);
+        av_log(NULL, AV_LOG_TRACE, "header='%s'\n", line);
 
         err = process_line(h, line, s->line_count, new_location);
         if (err < 0)
@@ -771,10 +782,11 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
 
                 s->chunksize = strtoll(line, NULL, 16);
 
-                av_dlog(NULL, "Chunked encoding data size: %"PRId64"'\n",
+                av_log(NULL, AV_LOG_TRACE, "Chunked encoding data size: %"PRId64"'\n",
                         s->chunksize);
-
-                if (!s->chunksize)
+                if (s->chunksize < 0)
+                    return AVERROR_INVALIDDATA;
+                else if (!s->chunksize)
                     return 0;
                 break;
             }
@@ -800,6 +812,32 @@ static int http_read_stream_all(URLContext *h, uint8_t *buf, int size)
     return pos;
 }
 
+static void update_metadata(HTTPContext *s, char *data)
+{
+    char *key;
+    char *val;
+    char *end;
+    char *next = data;
+
+    while (*next) {
+        key = next;
+        val = strstr(key, "='");
+        if (!val)
+            break;
+        end = strstr(val, "';");
+        if (!end)
+            break;
+
+        *val = '\0';
+        *end = '\0';
+        val += 2;
+
+        av_dict_set(&s->metadata, key, val, 0);
+
+        next = end + 2;
+    }
+}
+
 static int store_icy(URLContext *h, int size)
 {
     HTTPContext *s = h->priv_data;
@@ -828,6 +866,7 @@ static int store_icy(URLContext *h, int size)
             data[len + 1] = 0;
             if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
                 return ret;
+            update_metadata(s, data);
         }
         s->icy_data_read = 0;
         remaining        = s->icy_metaint;
@@ -975,7 +1014,7 @@ static const AVClass flavor ## _context_class = {   \
 #if CONFIG_HTTP_PROTOCOL
 HTTP_CLASS(http);
 
-URLProtocol ff_http_protocol = {
+const URLProtocol ff_http_protocol = {
     .name                = "http",
     .url_open2           = http_open,
     .url_read            = http_read,
@@ -993,7 +1032,7 @@ URLProtocol ff_http_protocol = {
 #if CONFIG_HTTPS_PROTOCOL
 HTTP_CLASS(https);
 
-URLProtocol ff_https_protocol = {
+const URLProtocol ff_https_protocol = {
     .name                = "https",
     .url_open2           = http_open,
     .url_read            = http_read,
@@ -1041,7 +1080,7 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags)
                 NULL);
 redo:
     ret = ffurl_open(&s->hd, lower_url, AVIO_FLAG_READ_WRITE,
-                     &h->interrupt_callback, NULL);
+                     &h->interrupt_callback, NULL, h->protocols, h);
     if (ret < 0)
         return ret;
 
@@ -1104,7 +1143,7 @@ static int http_proxy_write(URLContext *h, const uint8_t *buf, int size)
     return ffurl_write(s->hd, buf, size);
 }
 
-URLProtocol ff_httpproxy_protocol = {
+const URLProtocol ff_httpproxy_protocol = {
     .name                = "httpproxy",
     .url_open            = http_proxy_open,
     .url_read            = http_buf_read,