-
-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot retry err [...] after Request.Body was written; define Request.GetBody to avoid this error (affects h2 goaway and 307/308 redirects etc) #9
Comments
Hey Tim, Thanks for the report, would you be able to add an example program to reproduce the issue? Can also be in the form of a failing test case. Would make it clearer what the issue is and whether an eventual fix properly fixes this. To anyone interested and contributing the fix for that, I'd be happy to help review and merge the PR. Thanks, |
Here's a patch that adds a test that appears to cover the related "POST response is a redirect" case. It also sets up a framework to add related test cases. (The http.NewRequest() function automatically sets request.GetBody if the Body type is bytes.Buffer, bytes.Reader, or strings.Reader, and has done for years.) Uncomment the 307-redirect test to enable it. diff --git a/rehttp_mock_test.go b/rehttp_mock_test.go
index 8ddcd8b..b8a8377 100644
--- a/rehttp_mock_test.go
+++ b/rehttp_mock_test.go
@@ -117,24 +117,56 @@ func TestMockClientPreventRetryWithBody(t *testing.T) {
}
func TestMockClientRetryWithBody(t *testing.T) {
- retFn := func(att int, req *http.Request) (*http.Response, error) {
- return nil, tempErr{}
- }
- mock := &mockRoundTripper{t: t, retFn: retFn}
- tr := NewTransport(mock, RetryAll(RetryMaxRetries(1), RetryTemporaryErr()), ConstDelay(0))
+ newRequest := func(body io.Reader) *http.Request {
+ req, err := http.NewRequest("POST", "http://example.com", body)
+ assert.NoError(t, err)
+ req.Header.Set("Content-Type", "text/plain")
+ return req
+ }
- client := &http.Client{
- Transport: tr,
+ tests := []struct {
+ name string
+ req *http.Request
+ retFn func(att int, req *http.Request) (*http.Response, error)
+ err error
+ }{
+ {name: "temp-error",
+ req: newRequest(strings.NewReader("hello")),
+ retFn: func(att int, req *http.Request) (*http.Response, error) {
+ return nil, tempErr{}
+ },
+ err: tempErr{},
+ },
+ /* uncomment to test reproduce https://github.com/PuerkitoBio/rehttp/issues/9
+ {name: "307-redirect",
+ req: newRequest(strings.NewReader("hello")),
+ retFn: func(att int, req *http.Request) (*http.Response, error) {
+ if att >= 1 {
+ return &http.Response{StatusCode: 200}, nil
+ }
+ return &http.Response{StatusCode: 307}, nil
+ },
+ },
+ */
}
- _, err := client.Post("http://example.com", "text/plain", strings.NewReader("hello"))
- if assert.NotNil(t, err) {
- uerr, ok := err.(*url.Error)
- require.True(t, ok)
- assert.Equal(t, tempErr{}, uerr.Err)
+
+ for _, tt := range tests {
+ tt := tt
+ t.Run(tt.name, func(t *testing.T) {
+ mock := &mockRoundTripper{t: t, retFn: tt.retFn}
+
+ tr := NewTransport(mock, RetryAll(RetryMaxRetries(1), RetryTemporaryErr()), ConstDelay(0))
+
+ client := &http.Client{
+ Transport: tr,
+ }
+ _, err := client.Do(tt.req)
+ assert.ErrorIs(t, err, tt.err)
+ assert.Equal(t, 2, mock.Calls())
+ assert.Equal(t, []string{"hello", "hello"}, mock.Bodies())
+ })
}
- assert.Equal(t, 2, mock.Calls())
- assert.Equal(t, []string{"hello", "hello"}, mock.Bodies())
}
func TestMockClientRetryTimeout(t *testing.T) { |
Add tests with redirects, GetBody, addresses #9
@timbunce Hey Tim, following some back and forth discussion on the PR from Mohan who tried to address this issue, he made me realize that Note that there's still this issue that could improve Thanks, |
All sounds good. Many thanks to you and @openmohan for the investigation and analysis. |
The go-retryablehttp package was recently updated to handle retries with a body (hashicorp/go-retryablehttp#207 to fix hashicorp/go-retryablehttp#121).
A similar fix is needed for rehttp.
The text was updated successfully, but these errors were encountered: