PR #25635 opened by Marti2203
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25635
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25635.patch

Follow-up to #25505, from a pre-existing issue noted in the Forgejo_Fairy 
review there.

In single-client listen mode (`listen=1`), `http_listen()` returns handshake 
errors without closing `s->hd`, and `http_open()` returns that result directly 
instead of going through its `bail_out` cleanup, so `s->uri` and the other 
allocations are kept as well. Since `ffurl_connect()` only marks the context 
connected after a successful open, `http_close()` is never called for it.

A program that calls `avio_open2("http://127.0.0.1:18080";, AVIO_FLAG_WRITE, 
..., listen=1)` in a loop, with a client that sends `BOGUS\r\n\r\n` and hangs 
up each time, ends up with 26 open fds after 20 failed opens on master (6 
before). With this patch it stays at 6. `fate-http-status-line`, `fate-url` and 
`fate-api-seek` pass.

The patch closes the lower connection on failure in `http_listen()` and lets 
`http_open()` fall through to `bail_out`. It does not touch `http_close()`, so 
no `0\r\n\r\n` chunk footer can be sent to a client that never got a reply 
header.

Not covered here: in multi-client mode (`listen=2`), a context returned by 
`avio_accept()` is not marked connected until its handshake succeeds, so 
closing it after a failed handshake (or before any handshake, as the parent 
process in `doc/examples/avio_http_serve_files.c` does) also skips 
`http_close()` and keeps the accepted socket open. Fixing that needs 
`http_close()` to know whether a reply was sent, so it is left for a separate 
change.

This issue was found during an LLM review (Forgejo_Fairy, #25505); the fix was 
verified manually.

🤖 Generated with [Claude Code](https://claude.com/claude-code)



From d8dbe449a9ebec1f17bb9a545de82fa0524e4861 Mon Sep 17 00:00:00 2001
From: Martin Mirchev <[email protected]>
Date: Sat, 31 Oct 2026 13:47:50 +0800
Subject: [PATCH] avformat/http: close the connection if the single-client
 handshake fails

http_listen() returned handshake errors without closing the lower
connection, and http_open() returned the result of http_listen()
directly, so the URI and other allocations were not freed either.
ffurl_connect() marks the context connected only after a successful
open, so http_close() is not called afterwards and nothing else
releases them.

An application that calls avio_open2() with listen=1 in a loop leaked
one socket for every client whose request failed, e.g. a bad request
line or a client that hung up early.

Signed-off-by: Martin Mirchev <[email protected]>
---
 libavformat/http.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/libavformat/http.c b/libavformat/http.c
index 2f4f522363a..bab2719997d 100644
--- a/libavformat/http.c
+++ b/libavformat/http.c
@@ -809,6 +809,8 @@ static int http_listen(URLContext *h, const char *uri, int 
flags,
         while ((ret = http_handshake(h)) > 0);
     }
 fail:
+    if (ret < 0)
+        ffurl_closep(&s->hd);
     av_dict_free(&s->chained_options);
     av_dict_free(&s->cookie_dict);
     return ret;
@@ -858,10 +860,10 @@ static int http_open(URLContext *h, const char *uri, int 
flags,
         }
     }
 
-    if (s->listen) {
-        return http_listen(h, uri, flags, options);
-    }
-    ret = http_open_cnx(h, options, 0);
+    if (s->listen)
+        ret = http_listen(h, uri, flags, options);
+    else
+        ret = http_open_cnx(h, options, 0);
 bail_out:
     if (ret < 0) {
         av_dict_free(&s->chained_options);
-- 
2.54.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to