diff --git a/libavformat/http.c b/libavformat/http.c index c83309626e..fd5861ce25 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -326,11 +326,89 @@ static int http_get_line(HTTPContext *s, char *line, int line_size) } } +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" */ +static void parse_content_range(URLContext *h, char *p) +{ + HTTPContext *s = h->priv_data; + const char *slash; + + if (!strncmp(p, "bytes ", 6)) { + p += 6; + s->off = strtoll(p, NULL, 10); + if ((slash = strchr(p, '/')) && strlen(slash) > 0) + s->filesize = strtoll(slash+1, NULL, 10); + } + if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) + h->is_streamed = 0; /* we _can_ in fact seek */ +} + +static int parse_content_encoding(URLContext *h, char *p) +{ + 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); +#endif + } 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 0; +} + static int process_line(URLContext *h, char *line, int line_count, int *new_location) { HTTPContext *s = h->priv_data; char *tag, *p, *end; + int ret; /* end of header */ if (line[0] == '\0') { @@ -348,15 +426,8 @@ static int process_line(URLContext *h, char *line, int line_count, av_log(h, AV_LOG_DEBUG, "http_code=%d\n", s->http_code); - /* error codes are 4xx and 5xx, but regard 401 as a success, so we - * don't abort until all headers have been parsed. */ - if (s->http_code >= 400 && s->http_code < 600 && - (s->http_code != 401 || s->auth_state.auth_type != HTTP_AUTH_NONE) && - (s->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", s->http_code, end); - return AVERROR(EIO); - } + if ((ret = check_http_code(h, s->http_code, end)) < 0) + return ret; } else { while (*p != '\0' && *p != ':') p++; @@ -369,28 +440,13 @@ static int process_line(URLContext *h, char *line, int line_count, while (av_isspace(*p)) p++; if (!av_strcasecmp(tag, "Location")) { - 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; + if ((ret = parse_location(s, p)) < 0) + return ret; *new_location = 1; } else if (!av_strcasecmp(tag, "Content-Length") && s->filesize == -1) { s->filesize = strtoll(p, NULL, 10); } else if (!av_strcasecmp(tag, "Content-Range")) { - /* "bytes $from-$to/$document_size" */ - const char *slash; - if (!strncmp(p, "bytes ", 6)) { - p += 6; - s->off = strtoll(p, NULL, 10); - if ((slash = strchr(p, '/')) && strlen(slash) > 0) - s->filesize = strtoll(slash+1, NULL, 10); - } - if (s->seekable == -1 && (!s->is_akamai || s->filesize != 2147483647)) - h->is_streamed = 0; /* we _can_ in fact seek */ + parse_content_range(h, p); } else if (!av_strcasecmp(tag, "Accept-Ranges") && !strncmp(p, "bytes", 5) && s->seekable == -1) { @@ -441,30 +497,8 @@ static int process_line(URLContext *h, char *line, int line_count, av_freep(&s->icy_metadata_headers); s->icy_metadata_headers = buf; } else if (!av_strcasecmp(tag, "Content-Encoding")) { - 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); -#endif - } 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); - } + if ((ret = parse_content_encoding(h, p)) < 0) + return ret; } } return 1;