From 636273d3d4a8c42f51832e8bf83e566e875916bf Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 2 Mar 2014 20:26:19 +0100 Subject: [PATCH] http: handle ICY in presence of chunked transfer encoding Some http servers send an ICY stream in combination with chunked transfer encoding. This case was handled incorrectly by the ICY code: instead of handling chunked encoding before anything ICY related, both were mixed. Fix this by separating the ICY code from normal http reading. Move the normal http reading to a new function http_read_stream(), while http_read() handles ICY on top of http_read_stream(). The server identified itself as: cloudflare-nginx Signed-off-by: Michael Niedermayer --- libavformat/http.c | 54 +++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 69c4d6d7a0..7a0ba6cedd 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -768,7 +768,6 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) } if (len > 0) { s->off += len; - s->icy_data_read += len; if (s->chunksize > 0) s->chunksize -= len; } @@ -807,7 +806,7 @@ static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size) } #endif -static int http_read(URLContext *h, uint8_t *buf, int size) +static int http_read_stream(URLContext *h, uint8_t *buf, int size) { HTTPContext *s = h->priv_data; int err, new_location; @@ -842,6 +841,31 @@ static int http_read(URLContext *h, uint8_t *buf, int size) } size = FFMIN(size, s->chunksize); } +#if CONFIG_ZLIB + if (s->compressed) + return http_buf_read_compressed(h, buf, size); +#endif + return http_buf_read(h, buf, size); +} + +// Like http_read_stream(), but no short reads. +// Assumes partial reads are an error. +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 http_read(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + if (s->icy_metaint > 0) { int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ if (!remaining) { @@ -849,17 +873,18 @@ static int http_read(URLContext *h, uint8_t *buf, int size) // 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 follow. - int ch = http_getc(s); - if (ch < 0) - return ch; + uint8_t ch; + int len = http_read_stream_all(h, &ch, 1); + if (len < 1) + return len; if (ch > 0) { char data[255 * 16 + 1]; - int n; int ret; - ch *= 16; - for (n = 0; n < ch; n++) - data[n] = http_getc(s); - data[ch + 1] = 0; + len = ch * 16; + ret = http_read_stream_all(h, data, len); + if (ret < len) + return ret; + data[len + 1] = 0; if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) return ret; } @@ -868,11 +893,10 @@ static int http_read(URLContext *h, uint8_t *buf, int size) } size = FFMIN(size, remaining); } -#if CONFIG_ZLIB - if (s->compressed) - return http_buf_read_compressed(h, buf, size); -#endif - return http_buf_read(h, buf, size); + size = http_read_stream(h, buf, size); + if (size > 0) + s->icy_data_read += size; + return size; } /* used only when posting data */