From ef2ff8e65c329db4047042e2991598571ff06d38 Mon Sep 17 00:00:00 2001 From: ACHINTYA KULSHRESTHA Date: Wed, 12 Nov 2025 11:50:31 +0000 Subject: [PATCH] Fix ENHANCE_YOUR_CALM too_many_pings error for the proxy agent following https://blog.cloudflare.com/go-and-enhance-your-calm/ --- agent/utils/utils.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/agent/utils/utils.go b/agent/utils/utils.go index 0241717..880acee 100644 --- a/agent/utils/utils.go +++ b/agent/utils/utils.go @@ -371,13 +371,35 @@ func postResponseWithRetries(client *http.Client, proxyURL, backendID, requestID } continue } + // Force the response body to be fully read by copying it to the discard target. + // + // The response is expected to be empty for this specific case, so reading the entire + // response body should be safe and not cause any delays. + // + // The reason we do this is because under certain conditions (in particular, when + // using HTTP/2) the server and client might both try to close the underlying stream + // at the same time. When that happens, the client sends a PING message at the + // same time it sends the `RST_STREAM` message. + // + // If this happens a lot, it can trigger protections that a lot of server deployments + // have against PING flood attacks. + // + // Draining the response body forces the server-side `END_STREAM` message to + // arrive before the client tries to send the `RST_STREAM` message. In that case, + // the client will not send a PING and so will not trigger these PING flood protections. + // + // A future version of the Go standard library will likely change the client behavior + // so that it is more conservative about sending these PING messages, and if + // that happens then this line can be removed. The proposed change for that + // is https://go-review.git.corp.google.com/c/net/+/720300 + io.Copy(io.Discard, proxyResp.Body) proxyResp.Body.Close() if 500 <= proxyResp.StatusCode && proxyResp.StatusCode < 600 { if _, seekErr := proxyReadSeeker.Seek(0, io.SeekStart); seekErr != nil { return err } continue - } + } return nil } return err