@@ -26,6 +26,7 @@ import (
2626
2727 "github.com/matrix-org/complement/b"
2828 "github.com/matrix-org/complement/ct"
29+ "github.com/matrix-org/complement/internal"
2930)
3031
3132type ctxKey string
@@ -668,6 +669,9 @@ func (c *CSAPI) MustDo(t ct.TestLike, method string, paths []string, opts ...Req
668669// match.JSONKeyEqual("errcode", "M_INVALID_USERNAME"),
669670// },
670671// })
672+ //
673+ // The caller does not need to worry about closing the returned `http.Response.Body` as
674+ // this is handled automatically.
671675func (c * CSAPI ) Do (t ct.TestLike , method string , paths []string , opts ... RequestOpt ) * http.Response {
672676 t .Helper ()
673677 escapedPaths := make ([]string , len (paths ))
@@ -716,6 +720,30 @@ func (c *CSAPI) Do(t ct.TestLike, method string, paths []string, opts ...Request
716720 if err != nil {
717721 ct .Fatalf (t , "CSAPI.Do response returned error: %s" , err )
718722 }
723+ // `defer` is function scoped but it's okay that we only clean up all requests at
724+ // the end. To also be clear, `defer` arguments are evaluated at the time of the
725+ // `defer` statement so we are only closing the original response body here. Our new
726+ // response body will be untouched.
727+ defer internal .CloseIO (
728+ res .Body ,
729+ fmt .Sprintf (
730+ "CSAPI.Do: response body from %s %s" ,
731+ res .Request .Method ,
732+ res .Request .URL .String (),
733+ ),
734+ )
735+
736+ // Make a copy of the response body so that downstream callers can read it multiple
737+ // times if needed and don't need to worry about closing it.
738+ var resBody []byte
739+ if res .Body != nil {
740+ resBody , err = io .ReadAll (res .Body )
741+ if err != nil {
742+ ct .Fatalf (t , "CSAPI.Do failed to read response body for RetryUntil check: %s" , err )
743+ }
744+ res .Body = io .NopCloser (bytes .NewBuffer (resBody ))
745+ }
746+
719747 // debug log the response
720748 if c .Debug && res != nil {
721749 var dump []byte
@@ -725,19 +753,12 @@ func (c *CSAPI) Do(t ct.TestLike, method string, paths []string, opts ...Request
725753 }
726754 t .Logf ("%s" , string (dump ))
727755 }
756+
728757 if retryUntil == nil || retryUntil .timeout == 0 {
729758 return res // don't retry
730759 }
731760
732- // check the condition, make a copy of the response body first in case the check consumes it
733- var resBody []byte
734- if res .Body != nil {
735- resBody , err = io .ReadAll (res .Body )
736- if err != nil {
737- ct .Fatalf (t , "CSAPI.Do failed to read response body for RetryUntil check: %s" , err )
738- }
739- res .Body = io .NopCloser (bytes .NewBuffer (resBody ))
740- }
761+ // check the condition
741762 if retryUntil .untilFn (res ) {
742763 // remake the response and return
743764 res .Body = io .NopCloser (bytes .NewBuffer (resBody ))
0 commit comments