http: make length/offset-related variables unsigned.

Fixes #5992, reported and found by Paul Cher <paulcher@icloud.com>.
This commit is contained in:
Ronald S. Bultje 2016-12-05 08:02:33 -05:00
parent 51020adcec
commit 2a05c8f813

View File

@ -62,8 +62,8 @@ typedef struct HTTPContext {
int line_count; int line_count;
int http_code; int http_code;
/* Used if "Transfer-Encoding: chunked" otherwise -1. */ /* Used if "Transfer-Encoding: chunked" otherwise -1. */
int64_t chunksize; uint64_t chunksize;
int64_t off, end_off, filesize; uint64_t off, end_off, filesize;
char *location; char *location;
HTTPAuthState auth_state; HTTPAuthState auth_state;
HTTPAuthState proxy_auth_state; HTTPAuthState proxy_auth_state;
@ -95,9 +95,9 @@ typedef struct HTTPContext {
AVDictionary *cookie_dict; AVDictionary *cookie_dict;
int icy; int icy;
/* how much data was read since the last ICY metadata packet */ /* how much data was read since the last ICY metadata packet */
int icy_data_read; uint64_t icy_data_read;
/* after how many bytes of read data a new metadata packet will be found */ /* after how many bytes of read data a new metadata packet will be found */
int icy_metaint; uint64_t icy_metaint;
char *icy_metadata_headers; char *icy_metadata_headers;
char *icy_metadata_packet; char *icy_metadata_packet;
AVDictionary *metadata; AVDictionary *metadata;
@ -489,7 +489,7 @@ static int http_open(URLContext *h, const char *uri, int flags,
else else
h->is_streamed = 1; h->is_streamed = 1;
s->filesize = -1; s->filesize = UINT64_MAX;
s->location = av_strdup(uri); s->location = av_strdup(uri);
if (!s->location) if (!s->location)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
@ -616,9 +616,9 @@ static void parse_content_range(URLContext *h, const char *p)
if (!strncmp(p, "bytes ", 6)) { if (!strncmp(p, "bytes ", 6)) {
p += 6; p += 6;
s->off = strtoll(p, NULL, 10); s->off = strtoull(p, NULL, 10);
if ((slash = strchr(p, '/')) && strlen(slash) > 0) if ((slash = strchr(p, '/')) && strlen(slash) > 0)
s->filesize = strtoll(slash + 1, NULL, 10); s->filesize = strtoull(slash + 1, NULL, 10);
} }
if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647))
h->is_streamed = 0; /* we _can_ in fact seek */ h->is_streamed = 0; /* we _can_ in fact seek */
@ -808,8 +808,9 @@ static int process_line(URLContext *h, char *line, int line_count,
if ((ret = parse_location(s, p)) < 0) if ((ret = parse_location(s, p)) < 0)
return ret; return ret;
*new_location = 1; *new_location = 1;
} else if (!av_strcasecmp(tag, "Content-Length") && s->filesize == -1) { } else if (!av_strcasecmp(tag, "Content-Length") &&
s->filesize = strtoll(p, NULL, 10); s->filesize == UINT64_MAX) {
s->filesize = strtoull(p, NULL, 10);
} else if (!av_strcasecmp(tag, "Content-Range")) { } else if (!av_strcasecmp(tag, "Content-Range")) {
parse_content_range(h, p); parse_content_range(h, p);
} else if (!av_strcasecmp(tag, "Accept-Ranges") && } else if (!av_strcasecmp(tag, "Accept-Ranges") &&
@ -818,7 +819,7 @@ static int process_line(URLContext *h, char *line, int line_count,
h->is_streamed = 0; h->is_streamed = 0;
} else if (!av_strcasecmp(tag, "Transfer-Encoding") && } else if (!av_strcasecmp(tag, "Transfer-Encoding") &&
!av_strncasecmp(p, "chunked", 7)) { !av_strncasecmp(p, "chunked", 7)) {
s->filesize = -1; s->filesize = UINT64_MAX;
s->chunksize = 0; s->chunksize = 0;
} else if (!av_strcasecmp(tag, "WWW-Authenticate")) { } else if (!av_strcasecmp(tag, "WWW-Authenticate")) {
ff_http_auth_handle_header(&s->auth_state, tag, p); ff_http_auth_handle_header(&s->auth_state, tag, p);
@ -842,7 +843,7 @@ static int process_line(URLContext *h, char *line, int line_count,
if (parse_cookie(s, p, &s->cookie_dict)) if (parse_cookie(s, p, &s->cookie_dict))
av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p); av_log(h, AV_LOG_WARNING, "Unable to parse '%s'\n", p);
} else if (!av_strcasecmp(tag, "Icy-MetaInt")) { } else if (!av_strcasecmp(tag, "Icy-MetaInt")) {
s->icy_metaint = strtoll(p, NULL, 10); s->icy_metaint = strtoull(p, NULL, 10);
} else if (!av_strncasecmp(tag, "Icy-", 4)) { } else if (!av_strncasecmp(tag, "Icy-", 4)) {
if ((ret = parse_icy(s, tag, p)) < 0) if ((ret = parse_icy(s, tag, p)) < 0)
return ret; return ret;
@ -972,7 +973,7 @@ static int http_read_header(URLContext *h, int *new_location)
char line[MAX_URL_SIZE]; char line[MAX_URL_SIZE];
int err = 0; int err = 0;
s->chunksize = -1; s->chunksize = UINT64_MAX;
for (;;) { for (;;) {
if ((err = http_get_line(s, line, sizeof(line))) < 0) if ((err = http_get_line(s, line, sizeof(line))) < 0)
@ -1006,7 +1007,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
int post, err; int post, err;
char headers[HTTP_HEADERS_SIZE] = ""; char headers[HTTP_HEADERS_SIZE] = "";
char *authstr = NULL, *proxyauthstr = NULL; char *authstr = NULL, *proxyauthstr = NULL;
int64_t off = s->off; uint64_t off = s->off;
int len = 0; int len = 0;
const char *method; const char *method;
int send_expect_100 = 0; int send_expect_100 = 0;
@ -1060,7 +1061,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
// server supports seeking by analysing the reply headers. // server supports seeking by analysing the reply headers.
if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) { if (!has_header(s->headers, "\r\nRange: ") && !post && (s->off > 0 || s->end_off || s->seekable == -1)) {
len += av_strlcatf(headers + len, sizeof(headers) - len, len += av_strlcatf(headers + len, sizeof(headers) - len,
"Range: bytes=%"PRId64"-", s->off); "Range: bytes=%"PRIu64"-", s->off);
if (s->end_off) if (s->end_off)
len += av_strlcatf(headers + len, sizeof(headers) - len, len += av_strlcatf(headers + len, sizeof(headers) - len,
"%"PRId64, s->end_off - 1); "%"PRId64, s->end_off - 1);
@ -1135,7 +1136,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path,
s->line_count = 0; s->line_count = 0;
s->off = 0; s->off = 0;
s->icy_data_read = 0; s->icy_data_read = 0;
s->filesize = -1; s->filesize = UINT64_MAX;
s->willclose = 0; s->willclose = 0;
s->end_chunked_post = 0; s->end_chunked_post = 0;
s->end_header = 0; s->end_header = 0;
@ -1175,15 +1176,13 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size)
memcpy(buf, s->buf_ptr, len); memcpy(buf, s->buf_ptr, len);
s->buf_ptr += len; s->buf_ptr += len;
} else { } else {
int64_t target_end = s->end_off ? s->end_off : s->filesize; uint64_t target_end = s->end_off ? s->end_off : s->filesize;
if ((!s->willclose || s->chunksize < 0) && if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= target_end)
target_end >= 0 && s->off >= target_end)
return AVERROR_EOF; return AVERROR_EOF;
len = ffurl_read(s->hd, buf, size); len = ffurl_read(s->hd, buf, size);
if (!len && (!s->willclose || s->chunksize < 0) && if (!len && (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) {
target_end >= 0 && s->off < target_end) {
av_log(h, AV_LOG_ERROR, av_log(h, AV_LOG_ERROR,
"Stream ends prematurely at %"PRId64", should be %"PRId64"\n", "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n",
s->off, target_end s->off, target_end
); );
return AVERROR(EIO); return AVERROR(EIO);
@ -1247,7 +1246,7 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
return err; return err;
} }
if (s->chunksize >= 0) { if (s->chunksize != UINT64_MAX) {
if (!s->chunksize) { if (!s->chunksize) {
char line[32]; char line[32];
@ -1256,13 +1255,19 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
return err; return err;
} while (!*line); /* skip CR LF from last chunk */ } while (!*line); /* skip CR LF from last chunk */
s->chunksize = strtoll(line, NULL, 16); s->chunksize = strtoull(line, NULL, 16);
av_log(NULL, AV_LOG_TRACE, "Chunked encoding data size: %"PRId64"'\n", av_log(h, AV_LOG_TRACE,
"Chunked encoding data size: %"PRIu64"'\n",
s->chunksize); s->chunksize);
if (!s->chunksize) if (!s->chunksize)
return 0; return 0;
else if (s->chunksize == UINT64_MAX) {
av_log(h, AV_LOG_ERROR, "Invalid chunk size %"PRIu64"\n",
s->chunksize);
return AVERROR(EINVAL);
}
} }
size = FFMIN(size, s->chunksize); size = FFMIN(size, s->chunksize);
} }
@ -1273,17 +1278,17 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size)
read_ret = http_buf_read(h, buf, size); read_ret = http_buf_read(h, buf, size);
if ( (read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize) if ( (read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize)
|| (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) {
int64_t target = h->is_streamed ? 0 : s->off; uint64_t target = h->is_streamed ? 0 : s->off;
if (s->reconnect_delay > s->reconnect_delay_max) if (s->reconnect_delay > s->reconnect_delay_max)
return AVERROR(EIO); return AVERROR(EIO);
av_log(h, AV_LOG_INFO, "Will reconnect at %"PRId64" error=%s.\n", s->off, av_err2str(read_ret)); av_log(h, AV_LOG_INFO, "Will reconnect at %"PRIu64" error=%s.\n", s->off, av_err2str(read_ret));
av_usleep(1000U*1000*s->reconnect_delay); av_usleep(1000U*1000*s->reconnect_delay);
s->reconnect_delay = 1 + 2*s->reconnect_delay; s->reconnect_delay = 1 + 2*s->reconnect_delay;
seek_ret = http_seek_internal(h, target, SEEK_SET, 1); seek_ret = http_seek_internal(h, target, SEEK_SET, 1);
if (seek_ret != target) { if (seek_ret != target) {
av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRId64".\n", target); av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target);
return read_ret; return read_ret;
} }
@ -1338,10 +1343,11 @@ static int store_icy(URLContext *h, int size)
{ {
HTTPContext *s = h->priv_data; HTTPContext *s = h->priv_data;
/* until next metadata packet */ /* until next metadata packet */
int remaining = s->icy_metaint - s->icy_data_read; uint64_t remaining;
if (remaining < 0) if (s->icy_metaint < s->icy_data_read)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
remaining = s->icy_metaint - s->icy_data_read;
if (!remaining) { if (!remaining) {
/* The metadata packet is variable sized. It has a 1 byte header /* The metadata packet is variable sized. It has a 1 byte header
@ -1455,7 +1461,7 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo
{ {
HTTPContext *s = h->priv_data; HTTPContext *s = h->priv_data;
URLContext *old_hd = s->hd; URLContext *old_hd = s->hd;
int64_t old_off = s->off; uint64_t old_off = s->off;
uint8_t old_buf[BUFFER_SIZE]; uint8_t old_buf[BUFFER_SIZE];
int old_buf_size, ret; int old_buf_size, ret;
AVDictionary *options = NULL; AVDictionary *options = NULL;
@ -1466,7 +1472,7 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo
((whence == SEEK_CUR && off == 0) || ((whence == SEEK_CUR && off == 0) ||
(whence == SEEK_SET && off == s->off))) (whence == SEEK_SET && off == s->off)))
return s->off; return s->off;
else if ((s->filesize == -1 && whence == SEEK_END)) else if ((s->filesize == UINT64_MAX && whence == SEEK_END))
return AVERROR(ENOSYS); return AVERROR(ENOSYS);
if (whence == SEEK_CUR) if (whence == SEEK_CUR)
@ -1621,7 +1627,7 @@ redo:
s->buf_ptr = s->buffer; s->buf_ptr = s->buffer;
s->buf_end = s->buffer; s->buf_end = s->buffer;
s->line_count = 0; s->line_count = 0;
s->filesize = -1; s->filesize = UINT64_MAX;
cur_auth_type = s->proxy_auth_state.auth_type; cur_auth_type = s->proxy_auth_state.auth_type;
/* Note: This uses buffering, potentially reading more than the /* Note: This uses buffering, potentially reading more than the