FFmpeg 4.3.1 hls http(s)配新版Nginx WebDAV 无法删除切片bug

在使用FFmpeg进行hls推流输出时,发现配合新版Nginx (1.21) + WebDav组件的http服务器时,即使指定了m3u8切片数量以及删除无用切片的参数:

hls_list_size 5 -hls_flags delete_segments -hls

也没有在服务端正确删除无用切片,查看Nginx日志,发现每次FFmpeg发起的DELETE文件请求,都会跟随一个这样的报错:

DELETE with body is unsupported!

导致虽然FFmpeg删除文件的http请求到了Nginx,但实际并没有删除掉磁盘上的ts切片文件,时间一长,磁盘空间耗尽,然后就尴尬了…

追踪日志中的错误信息检查了下WebDAV模块的源码,发现在这次提交:http://hg.nginx.org/nginx/rev/f609c0ac2972 时,加入了这样的代码:

--- a/src/http/modules/ngx_http_dav_module.c	Mon Dec 23 18:56:21 2019 +0300
+++ b/src/http/modules/ngx_http_dav_module.c	Mon Dec 23 20:39:27 2019 +0300
@@ -312,7 +312,7 @@
     ngx_file_info_t           fi;
     ngx_http_dav_loc_conf_t  *dlcf;
 
-    if (r->headers_in.content_length_n > 0) {
+    if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "DELETE with body is unsupported");
         return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
@@ -495,7 +495,7 @@
     size_t     root;
     ngx_str_t  path;
 
-    if (r->headers_in.content_length_n > 0) {
+    if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                       "MKCOL with body is unsupported");
         return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
@@ -549,7 +549,9 @@
     ngx_http_dav_copy_ctx_t   copy;
     ngx_http_dav_loc_conf_t  *dlcf;
 
-    if (r->headers_in.content_length_n > 0) {
+    if (r->headers_in.content_length_n > 0 || r->headers_in.chunked) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "COPY and MOVE with body are unsupported");
         return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
     }

除了检测请求header中的content_length之外,还额外检查了是否为chunked请求,问题就出在这里!content length肯定没问题,FFmpeg在DELETE时没有发送任何请求body,但是这个chunked嘛…看了下FFmpeg的源码,ffmpeg-4.3.1/libavformat/http.c中的http_connect函数里:

    if (post && s->chunked_post)
        av_bprintf(&request, "Transfer-Encoding: chunked\r\n");

所以,FFmpeg的处理逻辑是无论什么请求,只要标记了chunked,就都会加上“Transfer-Encoding: chunked”这个header,很显然这个逻辑就和新版WebDAV的逻辑不对付了,同时查了下FFmpeg此时最新代码,发现http.c中依然是这么处理的,虽然貌似可以通过chunked_post这个参数回避这个逻辑,但如果不区分请求类型无脑关闭chunked话,那真正上传切片文件的请求估计又会受到影响,于是做出如下修改:

    if (post && s->chunked_post && 0 != strcmp(method, "DELETE"))
        av_bprintf(&request, "Transfer-Encoding: chunked\r\n");

对DELETE请求特殊处理,不增加chunked header,重新编译出ffmpeg测试,问题解决。

博主友情提示:

如您在评论中需要提及如QQ号、电子邮件地址或其他隐私敏感信息,欢迎使用>>博主专用加密工具v3<<处理后发布,原文只有博主可以看到。