]> 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, 28 Aug 2025 08:43:22 +0000 (10:43 +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>
(cherry picked from commit b81ed956d2f0b6bc538b34ee7e7ad304be233e7a)

pdns/dnsdistdist/dnsdist-nghttp2-in.cc
pdns/dnsdistdist/dnsdist-nghttp2-in.hh

index 62fde3d9bb52a1e6f274c4c78b050a1f90aafaed..d62846829bfd24ae74d634f80afaed27011b6f3b 100644 (file)
@@ -745,17 +745,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;
   }
 
@@ -951,9 +952,16 @@ int IncomingHTTP2Connection::on_stream_close_callback(nghttp2_session* session,
 {
   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 16da4deb5420b788e7262011bbfda4b302f10b6b..4bec5f8c968dc29a74eba68a6529c747f2b40d22 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);