Loading debian/changelog +10 −0 Original line number Diff line number Diff line mediadb (20260503+8) unstable; urgency=high * server/import: fix logic bug for HTTP/3 import sessions where client disconnects could leave orphaned session state and import_running stuck, causing later PUT /api/import to return "import not available" * server/import: add stale H3 session recovery with activity timeout and robust cleanup before accepting new H3 import streams -- Jan Koester <jan.koester@tuxist.de> Sun, 03 May 2026 19:20:00 +0200 mediadb (20260503+7) unstable; urgency=high * cluster/import: speed up synchronous media replication by removing Loading src/server.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -539,6 +539,24 @@ void MediaHttpEvent::onH2DataChunk(libhttppp::HttpRequest &conn, uint32_t stream bool MediaHttpEvent::onH3StreamHeaders(netplus::socket *sock, uint64_t streamId, const std::vector<libhttppp::qpack::HeaderField> &headers) { // Recover from orphaned H3 imports (e.g. client disconnect mid-upload). // H1/H2 are cleaned in DisconnectEvent; H3 needs explicit stale cleanup. { constexpr auto kStaleTimeout = std::chrono::seconds(120); auto now = std::chrono::steady_clock::now(); for (auto it = h3_imports_.begin(); it != h3_imports_.end();) { bool stale = (now - it->second.last_activity) > kStaleTimeout; bool done = it->second.session && it->second.session->done(); if (stale || done) { it = h3_imports_.erase(it); app_.finish_import(false, stale ? "stale h3 import session" : "h3 import session finished unexpectedly"); } else { ++it; } } } std::string method, path; for (auto &hf : headers) { if (hf.name == ":method") method = hf.value; Loading Loading @@ -570,6 +588,7 @@ void MediaHttpEvent::onH3DataChunk(netplus::socket *sock, uint64_t streamId, if (it == h3_imports_.end()) return; auto &state = it->second; state.last_activity = std::chrono::steady_clock::now(); if (data && len > 0) { state.session->feed(data, len); state.bytes_written += len; Loading src/server.h +3 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include <netplus/socket.h> #include <atomic> #include <chrono> #include <string> #include <unordered_map> #include <vector> Loading @@ -30,6 +31,8 @@ struct ImportState { std::unique_ptr<ImportSession> session; size_t content_length = 0; size_t bytes_written = 0; std::chrono::steady_clock::time_point started_at = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point last_activity = started_at; }; MediaConExt* getMediaExt(libhttppp::HttpRequest& req); Loading Loading
debian/changelog +10 −0 Original line number Diff line number Diff line mediadb (20260503+8) unstable; urgency=high * server/import: fix logic bug for HTTP/3 import sessions where client disconnects could leave orphaned session state and import_running stuck, causing later PUT /api/import to return "import not available" * server/import: add stale H3 session recovery with activity timeout and robust cleanup before accepting new H3 import streams -- Jan Koester <jan.koester@tuxist.de> Sun, 03 May 2026 19:20:00 +0200 mediadb (20260503+7) unstable; urgency=high * cluster/import: speed up synchronous media replication by removing Loading
src/server.cpp +19 −0 Original line number Diff line number Diff line Loading @@ -539,6 +539,24 @@ void MediaHttpEvent::onH2DataChunk(libhttppp::HttpRequest &conn, uint32_t stream bool MediaHttpEvent::onH3StreamHeaders(netplus::socket *sock, uint64_t streamId, const std::vector<libhttppp::qpack::HeaderField> &headers) { // Recover from orphaned H3 imports (e.g. client disconnect mid-upload). // H1/H2 are cleaned in DisconnectEvent; H3 needs explicit stale cleanup. { constexpr auto kStaleTimeout = std::chrono::seconds(120); auto now = std::chrono::steady_clock::now(); for (auto it = h3_imports_.begin(); it != h3_imports_.end();) { bool stale = (now - it->second.last_activity) > kStaleTimeout; bool done = it->second.session && it->second.session->done(); if (stale || done) { it = h3_imports_.erase(it); app_.finish_import(false, stale ? "stale h3 import session" : "h3 import session finished unexpectedly"); } else { ++it; } } } std::string method, path; for (auto &hf : headers) { if (hf.name == ":method") method = hf.value; Loading Loading @@ -570,6 +588,7 @@ void MediaHttpEvent::onH3DataChunk(netplus::socket *sock, uint64_t streamId, if (it == h3_imports_.end()) return; auto &state = it->second; state.last_activity = std::chrono::steady_clock::now(); if (data && len > 0) { state.session->feed(data, len); state.bytes_written += len; Loading
src/server.h +3 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #include <netplus/socket.h> #include <atomic> #include <chrono> #include <string> #include <unordered_map> #include <vector> Loading @@ -30,6 +31,8 @@ struct ImportState { std::unique_ptr<ImportSession> session; size_t content_length = 0; size_t bytes_written = 0; std::chrono::steady_clock::time_point started_at = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point last_activity = started_at; }; MediaConExt* getMediaExt(libhttppp::HttpRequest& req); Loading