diff --git a/conjure-go-client/httpclient/body_handler_test.go b/conjure-go-client/httpclient/body_handler_test.go index 18d162c1..efb20e17 100644 --- a/conjure-go-client/httpclient/body_handler_test.go +++ b/conjure-go-client/httpclient/body_handler_test.go @@ -17,6 +17,7 @@ package httpclient_test import ( "bytes" "context" + "io" "io/ioutil" "net/http" "net/http/httptest" @@ -85,7 +86,9 @@ func TestRawBody(t *testing.T) { resp, err := client.Do(context.Background(), httpclient.WithRequestMethod(http.MethodPost), - httpclient.WithRawRequestBody(ioutil.NopCloser(bytes.NewBuffer(reqVar))), + httpclient.WithRawRequestBodyProvider(func() io.ReadCloser { + return ioutil.NopCloser(bytes.NewBuffer(reqVar)) + }), httpclient.WithRawResponseBody(), ) assert.NoError(t, err) @@ -99,3 +102,32 @@ func TestRawBody(t *testing.T) { assert.NotNil(t, resp) assert.Equal(t, respVar, gotRespBytes) } + +func TestRawRequestRetry(t *testing.T) { + count := 0 + requestBytes := []byte{12, 13} + + server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + gotReqBytes, err := ioutil.ReadAll(req.Body) + assert.NoError(t, err) + assert.Equal(t, requestBytes, gotReqBytes) + if count == 0 { + rw.WriteHeader(http.StatusBadRequest) + } + // Otherwise 200 is returned + count++ + })) + defer server.Close() + + client, err := httpclient.NewClient(httpclient.WithBaseURLs([]string{server.URL})) + assert.NoError(t, err) + + _, err = client.Do( + context.Background(), + httpclient.WithRawRequestBodyProvider(func() io.ReadCloser { + return ioutil.NopCloser(bytes.NewReader(requestBytes)) + }), + httpclient.WithRequestMethod(http.MethodPost)) + assert.NoError(t, err) + assert.Equal(t, 2, count) +} diff --git a/conjure-go-client/httpclient/request_params.go b/conjure-go-client/httpclient/request_params.go index abb4ea52..882e64dd 100644 --- a/conjure-go-client/httpclient/request_params.go +++ b/conjure-go-client/httpclient/request_params.go @@ -103,9 +103,30 @@ func WithRequestBody(input interface{}, encoder codecs.Encoder) RequestParam { // input, _ := os.Open("file.txt") // resp, err := client.Do(..., WithRawRequestBody(input), ...) // +// Deprecated: Retries don't include the body for WithRawRequestBody. +// Use WithRawRequestBodyProvider for full retry support. func WithRawRequestBody(input io.ReadCloser) RequestParam { + return WithRawRequestBodyProvider(func() io.ReadCloser { + return input + }) +} + +// WithRawRequestBodyProvider uses the io.ReadCloser provided by +// getBody as the request body. The getBody parameter must not be nil. +// Example: +// +// provider := func() io.ReadCloser { +// input, _ := os.Open("file.txt") +// return input +// } +// resp, err := client.Do(..., WithRawRequestBodyProvider(provider), ...) +// +func WithRawRequestBodyProvider(getBody func() io.ReadCloser) RequestParam { return requestParamFunc(func(b *requestBuilder) error { - b.bodyMiddleware.requestInput = input + if getBody == nil { + return werror.Error("getBody can not be nil") + } + b.bodyMiddleware.requestInput = getBody() b.bodyMiddleware.requestEncoder = nil b.headers.Set("Content-Type", "application/octet-stream") return nil