@@ -7,12 +7,21 @@ import (
77 "bytes"
88 "context"
99 "fmt"
10+ "io"
1011 "net/http"
1112 "net/url"
1213
1314 rpc "github.com/gorilla/rpc/v2/json2"
1415)
1516
17+ // CleanlyCloseBody avoids sending unnecessary RST_STREAM and PING frames by
18+ // ensuring the whole body is read before being closed.
19+ // See https://blog.cloudflare.com/go-and-enhance-your-calm/#reading-bodies-in-go-can-be-unintuitive
20+ func CleanlyCloseBody (body io.ReadCloser ) {
21+ _ , _ = io .Copy (io .Discard , body )
22+ _ = body .Close ()
23+ }
24+
1625func SendJSONRequest (
1726 ctx context.Context ,
1827 uri * url.URL ,
@@ -42,22 +51,21 @@ func SendJSONRequest(
4251 request .Header = ops .headers
4352 request .Header .Set ("Content-Type" , "application/json" )
4453
54+ //nolint:bodyclose // body is closed via CleanlyCloseBody
4555 resp , err := http .DefaultClient .Do (request )
4656 if err != nil {
4757 return fmt .Errorf ("failed to issue request: %w" , err )
4858 }
59+ defer CleanlyCloseBody (resp .Body )
4960
5061 // Return an error for any non successful status code
5162 if resp .StatusCode < 200 || resp .StatusCode > 299 {
52- // Drop any error during close to report the original error
53- _ = resp .Body .Close ()
5463 return fmt .Errorf ("received status code: %d" , resp .StatusCode )
5564 }
5665
5766 if err := rpc .DecodeClientResponse (resp .Body , reply ); err != nil {
58- // Drop any error during close to report the original error
59- _ = resp .Body .Close ()
6067 return fmt .Errorf ("failed to decode client response: %w" , err )
6168 }
62- return resp .Body .Close ()
69+
70+ return nil
6371}
0 commit comments