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 <michaelni@gmx.at>
This commit is contained in:
wm4 2014-03-02 20:26:19 +01:00 committed by Michael Niedermayer
parent 9deecdf85f
commit 636273d3d4
1 changed files with 39 additions and 15 deletions

View File

@ -768,7 +768,6 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
} }
if (len > 0) { if (len > 0) {
s->off += len; s->off += len;
s->icy_data_read += len;
if (s->chunksize > 0) if (s->chunksize > 0)
s->chunksize -= len; s->chunksize -= len;
} }
@ -807,7 +806,7 @@ static int http_buf_read_compressed(URLContext *h, uint8_t *buf, int size)
} }
#endif #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; HTTPContext *s = h->priv_data;
int err, new_location; int err, new_location;
@ -842,6 +841,31 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
} }
size = FFMIN(size, s->chunksize); 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) { if (s->icy_metaint > 0) {
int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */ int remaining = s->icy_metaint - s->icy_data_read; /* until next metadata packet */
if (!remaining) { 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, // 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 // the metadata doesn't change. After the packet, icy_metaint bytes
// of normal data follow. // of normal data follow.
int ch = http_getc(s); uint8_t ch;
if (ch < 0) int len = http_read_stream_all(h, &ch, 1);
return ch; if (len < 1)
return len;
if (ch > 0) { if (ch > 0) {
char data[255 * 16 + 1]; char data[255 * 16 + 1];
int n;
int ret; int ret;
ch *= 16; len = ch * 16;
for (n = 0; n < ch; n++) ret = http_read_stream_all(h, data, len);
data[n] = http_getc(s); if (ret < len)
data[ch + 1] = 0; return ret;
data[len + 1] = 0;
if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0) if ((ret = av_opt_set(s, "icy_metadata_packet", data, 0)) < 0)
return ret; return ret;
} }
@ -868,11 +893,10 @@ static int http_read(URLContext *h, uint8_t *buf, int size)
} }
size = FFMIN(size, remaining); size = FFMIN(size, remaining);
} }
#if CONFIG_ZLIB size = http_read_stream(h, buf, size);
if (s->compressed) if (size > 0)
return http_buf_read_compressed(h, buf, size); s->icy_data_read += size;
#endif return size;
return http_buf_read(h, buf, size);
} }
/* used only when posting data */ /* used only when posting data */