From e11cec1059cd2e183be2ce0b7ab4b29a173667f7 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Tue, 23 Jun 2026 16:16:59 +0200 Subject: [PATCH] avformat/libcurl: respect format whitelist And also set a reasonable default whitelist. This is especially important because libcurl supports a much wider range of protocols than FFmpeg, including e.g. smtps, telnet, gopher, etc. We have to include "libcurl" in libcurl's own default whitelist, otherwise it will refuse te recursively open itself for e.g. HLS. Sponsored-by: nxtedition AB Signed-off-by: Niklas Haas --- libavformat/libcurl.c | 45 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/libavformat/libcurl.c b/libavformat/libcurl.c index 26a2ccf8a1..44054d16df 100644 --- a/libavformat/libcurl.c +++ b/libavformat/libcurl.c @@ -28,6 +28,7 @@ #include #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/error.h" #include "libavutil/fifo.h" #include "libavutil/log.h" @@ -699,6 +700,44 @@ static struct curl_slist *build_headers(CurlContext *c) return list; } +static int setup_protocols(CurlContext *c) +{ + const char *wl = c->h->protocol_whitelist; + const char *bl = c->h->protocol_blacklist; + if (!wl && !bl) + return 0; + + AVBPrint bp; + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); + + curl_version_info_data *info = curl_version_info(CURLVERSION_NOW); + for (const char *const *p = info->protocols; *p; p++) { + const char *proto = *p; + if (av_strcasecmp(proto, "http") && av_strcasecmp(proto, "https")) + continue; /* only http(s) are supported by libcurl.c at the moment */ + if (wl && av_match_list(proto, wl, ',') <= 0) + continue; + if (bl && av_match_list(proto, bl, ',') > 0) + continue; + if (bp.len) + av_bprint_chars(&bp, ',', 1); + av_bprintf(&bp, "%s", proto); + } + + if (!av_bprint_is_complete(&bp)) + return AVERROR(ENOMEM); + + if (!bp.len) { + av_log(c->h, AV_LOG_ERROR, "Set of allowed protocols is empty.\n"); + return AVERROR(EINVAL); + } + + curl_easy_setopt(c->easy, CURLOPT_PROTOCOLS_STR, bp.str); + curl_easy_setopt(c->easy, CURLOPT_REDIR_PROTOCOLS_STR, bp.str); + av_bprint_finalize(&bp, NULL); + return 0; +} + static void setup_curl(CurlContext *c) { CURL *e = c->easy; @@ -857,6 +896,11 @@ static int libcurl_open(URLContext *h, const char *url, int flags, ret = AVERROR(ENOMEM); goto fail; } + + ret = setup_protocols(c); + if (ret < 0) + goto fail; + setup_curl(c); ret = curl_dispatch(c->loop, CMD_ADD, c, 0, 0); @@ -1042,4 +1086,5 @@ const URLProtocol ff_libcurl_protocol = { .priv_data_size = sizeof(CurlContext), .priv_data_class = &libcurl_context_class, .flags = URL_PROTOCOL_FLAG_NETWORK, + .default_whitelist = "http,https,libcurl", };