This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit e48a073d7e4a7053e6f89d64e3dbb11fef41f0b0 Author: Romain Beauxis <[email protected]> AuthorDate: Sun Aug 23 21:19:07 2026 -0500 Commit: Romain Beauxis <[email protected]> CommitDate: Thu Aug 27 13:43:01 2026 +0000 avformat/http: reject malformed response status lines A status line carrying no HTTP version parsed as status code 0, which check_http_code() then accepted as a success: the body of an error reply, or of a reply from something that is not an HTTP server at all, was handed to the demuxer. strtol() was equally lenient about the code itself, accepting a sign, a count of digits other than three, and a value outside the range HTTP defines. Parse the grammar RFC 9112 actually specifies: a case sensitive "HTTP/" followed by DIGIT "." DIGIT, then exactly three digits on a whitespace boundary, and reject a code outside the 100-599 range of RFC 9110 section 15. A status line with no reason phrase at all, "HTTP/1.1 200", stays accepted; the separator RFC 9112 requires there is missing often enough in the wild. reason now points at the phrase itself rather than at the separator before it, so check_http_code() no longer has to skip that separator on its own. Worth noting: this invalidates several class of previously accepted invalid http responses, include the ICY responses class from legacy shoutcast servers. ICY responses are planned on being re-introduced as opt-in via the new libcurl HTTP stack. --- libavformat/http.c | 39 ++++++++++++++++++++++++++------------ tests/ref/fate/http-status-line | 42 ++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 33 deletions(-) diff --git a/libavformat/http.c b/libavformat/http.c index 50fd88970d..fff0f25e36 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -892,26 +892,42 @@ static int http_get_line(HTTPContext *s, char *line, int line_size) int ff_http_parse_status_line(void *logctx, const char *line, HTTPStatusLine *st) { - const char *p = line; - char *end; + const char *p; memset(st, 0, sizeof(*st)); - if (av_strncasecmp(p, "HTTP/1.0", 8) == 0) - st->willclose = 1; + if (!av_strstart(line, "HTTP/", &p) || + !av_isdigit(p[0]) || p[1] != '.' || !av_isdigit(p[2]) || + !av_isspace(p[3])) { + av_log(logctx, AV_LOG_ERROR, "Malformed HTTP status line.\n"); + return AVERROR_INVALIDDATA; + } - while (*p != '/' && *p != '\0') - p++; - while (*p == '/') - p++; av_strlcpy(st->version, p, sizeof(st->version)); + st->willclose = !strcmp(st->version, "1.0"); - while (!av_isspace(*p) && *p != '\0') + p += 3; + while (av_isspace(*p)) p++; + + /* RFC 9112 mandates a space after the code, but a bare "HTTP/1.1 200" + * is common enough in the wild to be worth accepting. */ + if (!av_isdigit(p[0]) || !av_isdigit(p[1]) || !av_isdigit(p[2]) || + (p[3] && !av_isspace(p[3]))) { + av_log(logctx, AV_LOG_ERROR, "Malformed HTTP status code.\n"); + return AVERROR_INVALIDDATA; + } + + st->code = 100 * (p[0] - '0') + 10 * (p[1] - '0') + p[2] - '0'; + if (st->code < 100 || st->code > 599) { + av_log(logctx, AV_LOG_ERROR, "HTTP status code %d out of range.\n", + st->code); + return AVERROR_INVALIDDATA; + } + p += 3; while (av_isspace(*p)) p++; - st->code = strtol(p, &end, 10); - st->reason = end; + st->reason = p; av_log(logctx, AV_LOG_TRACE, "http_code=%d\n", st->code); @@ -926,7 +942,6 @@ static int check_http_code(URLContext *h, int http_code, const char *end) 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 ff_http_averror(http_code, AVERROR(EIO)); } diff --git a/tests/ref/fate/http-status-line b/tests/ref/fate/http-status-line index 503ed9a59a..ae75ad9377 100644 --- a/tests/ref/fate/http-status-line +++ b/tests/ref/fate/http-status-line @@ -1,44 +1,44 @@ "HTTP/1.1 200 OK" - version="1.1" code=200 willclose=0 reason=" OK" + version="1.1" code=200 willclose=0 reason="OK" "HTTP/1.0 200 OK" - version="1.0" code=200 willclose=1 reason=" OK" + version="1.0" code=200 willclose=1 reason="OK" "HTTP/1.1 404 Not Found" - version="1.1" code=404 willclose=0 reason=" Not Found" + version="1.1" code=404 willclose=0 reason="Not Found" "HTTP/1.1 500 Internal Server Error" - version="1.1" code=500 willclose=0 reason=" Internal Server Error" + version="1.1" code=500 willclose=0 reason="Internal Server Error" "HTTP/1.1 204 No Content" - version="1.1" code=204 willclose=0 reason=" No Content" + version="1.1" code=204 willclose=0 reason="No Content" "HTTP/1.1 200" version="1.1" code=200 willclose=0 reason="" "HTTP/1.1" - version="1.1" code=0 willclose=0 reason="" + rejected "HTTP/1.1 OK" - version="1.1" code=0 willclose=0 reason="OK" + rejected "HTTP" - version="" code=0 willclose=0 reason="" + rejected "200 OK" - version="" code=0 willclose=0 reason="" + rejected "NOT A STATUS LINE" - version="" code=0 willclose=0 reason="" + rejected "" - version="" code=0 willclose=0 reason="" + rejected "ICY 200 OK" - version="" code=0 willclose=0 reason="" + rejected "ICY 404 Not Found" - version="" code=0 willclose=0 reason="" + rejected "HTTP/1.1 200OK" - version="1.1" code=200 willclose=0 reason="OK" + rejected "HTTP/1.1 +200 Plus" - version="1.1" code=200 willclose=0 reason=" Plus" + rejected "HTTP/1.1 20 Short" - version="1.1" code=20 willclose=0 reason=" Short" + rejected "HTTP/1.1 2000 Four" - version="1.1" code=2000 willclose=0 reason=" Four" + rejected "HTTP/x 200 Bad version" - version="x 2" code=200 willclose=0 reason=" Bad version" + rejected "http/1.1 200 lowercase" - version="1.1" code=200 willclose=0 reason=" lowercase" + rejected "HTTP/1.1 099 Too low" - version="1.1" code=99 willclose=0 reason=" Too low" + rejected "HTTP/1.1 600 Too high" - version="1.1" code=600 willclose=0 reason=" Too high" + rejected -- To stop receiving notification emails like this one, please contact [email protected]. _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
