]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Fix the accounting of "killed" streams
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 28 Jul 2025 14:31:36 +0000 (16:31 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 21 Aug 2025 10:28:37 +0000 (12:28 +0200)
The way the nghttp2 library works means that we can get notified
that a stream has been closed while we are still in the function
sending the actual response. This is not a "killed" stream, but
just a regular closure.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
pdns/dnsdistdist/dnsdist-nghttp2-in.cc
pdns/dnsdistdist/dnsdist-nghttp2-in.hh

index 2ada93a4a943d096d8f12f8aca83272dd3a92f9f..56d6c52a852c4ec904e5f2e107d2f331319ff2d0 100644 (file)
@@ -752,17 +752,18 @@ bool IncomingHTTP2Connection::sendResponse(IncomingHTTP2Connection::StreamID str
     NGHTTP2Headers::addCustomDynamicHeader(headers, key, value);
   }
 
+  context.d_sendingResponse = true;
   auto ret = nghttp2_submit_response(d_session.get(), streamID, headers.data(), headers.size(), &data_provider);
   if (ret != 0) {
-    d_currentStreams.erase(streamID);
     vinfolog("Error submitting HTTP response for stream %d: %s", streamID, nghttp2_strerror(ret));
+    d_currentStreams.erase(streamID);
     return false;
   }
 
   ret = nghttp2_session_send(d_session.get());
   if (ret != 0) {
-    d_currentStreams.erase(streamID);
     vinfolog("Error flushing HTTP response for stream %d: %s", streamID, nghttp2_strerror(ret));
+    d_currentStreams.erase(streamID);
     return false;
   }
 
@@ -958,9 +959,16 @@ int IncomingHTTP2Connection::on_stream_close_callback(nghttp2_session* session,
   (void)error_code;
   auto* conn = static_cast<IncomingHTTP2Connection*>(user_data);
 
-  if (conn->d_currentStreams.erase(stream_id) > 0) {
+  auto streamIt = conn->d_currentStreams.find(stream_id);
+  if (streamIt == conn->d_currentStreams.end()) {
+    return 0;
+  }
+
+  if (!streamIt->second.d_sendingResponse) {
     conn->d_killedStreams.emplace(stream_id);
   }
+
+  conn->d_currentStreams.erase(streamIt);
   return 0;
 }
 
index 36e142151cfbb30371e859bcbc32a41d2714dea2..e14eee439522485b837194a5b643263b21d96530 100644 (file)
@@ -55,6 +55,7 @@ public:
     size_t d_queryPos{0};
     uint32_t d_statusCode{0};
     Method d_method{Method::Unknown};
+    bool d_sendingResponse{false};
   };
 
   IncomingHTTP2Connection(ConnectionInfo&& connectionInfo, TCPClientThreadData& threadData, const struct timeval& now);