Skip to content

Commit

Permalink
feat: handle empty get body (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
KarlGW authored Dec 17, 2024
1 parent b070184 commit ec25d3d
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 3 deletions.
32 changes: 29 additions & 3 deletions transport.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package httpr

import (
"bytes"
"io"
"net/http"
"time"
Expand Down Expand Up @@ -51,9 +52,8 @@ func New(options ...Option) *Transport {
// 408, 429, 500, 502, 503 and 504.
var NewTransport = New

// RoundTrip satisfies the http.RoundTripper interface and performs an
// http request with the configured retry policy.
func (tr *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
// setup sets the default values for the transport when they are not provided.
func (tr *Transport) setup() {
if tr.tr == nil {
tr.tr = http.DefaultTransport
}
Expand All @@ -70,6 +70,17 @@ func (tr *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
return 0
}
}
}

// RoundTrip satisfies the http.RoundTripper interface and performs an
// http request with the configured retry policy.
func (tr *Transport) RoundTrip(r *http.Request) (*http.Response, error) {
tr.setup()
if r.Body != nil && r.GetBody == nil {
if err := setGetBody(r); err != nil {
return nil, err
}
}
backoff := tr.rp.Backoff

retries := 0
Expand Down Expand Up @@ -127,3 +138,18 @@ func drainResponse(r *http.Response) error {
}
return nil
}

// setGetBody sets the GetBody method on the request
func setGetBody(r *http.Request) error {
body, err := io.ReadAll(r.Body)
if err != nil {
return err
}
r.Body = io.NopCloser(bytes.NewReader(body))
r.ContentLength = int64(len(body))

r.GetBody = func() (io.ReadCloser, error) {
return io.NopCloser(bytes.NewReader(body)), nil
}
return nil
}
79 changes: 79 additions & 0 deletions transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,64 @@ import (
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)

func TestNew(t *testing.T) {
var tests = []struct {
name string
input []Option
want *Transport
}{
{
name: "default transport",
want: &Transport{
tr: http.DefaultTransport,
rp: defaultRetryPolicy(),
},
},
{
name: "with retry policy",
input: []Option{
WithRetryPolicy(RetryPolicy{
ShouldRetry: StandardShouldRetry,
Backoff: ExponentialBackoff(),
MaxRetries: 5,
MinDelay: 1 * time.Second,
MaxDelay: 10 * time.Second,
Jitter: 0.1,
}),
},
want: &Transport{
tr: http.DefaultTransport,
rp: RetryPolicy{
ShouldRetry: StandardShouldRetry,
Backoff: ExponentialBackoff(),
MaxRetries: 5,
MinDelay: 1 * time.Second,
MaxDelay: 10 * time.Second,
Jitter: 0.1,
},
},
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
got := New(test.input...)

if diff := cmp.Diff(test.want, got, cmp.AllowUnexported(Transport{}, http.Transport{}), cmpopts.IgnoreUnexported(http.Transport{}), cmpopts.IgnoreFields(RetryPolicy{}, "ShouldRetry", "Backoff"), cmpopts.IgnoreFields(http.Transport{}, "Proxy", "DialContext")); diff != "" {
t.Errorf("New() = unexpected result (-want +got)\n%s\n", diff)
}
})
}
}

func TestTransport_RoundTrip(t *testing.T) {
type input struct {
req func() *http.Request
Expand Down Expand Up @@ -165,6 +217,33 @@ func TestTransport_RoundTrip(t *testing.T) {
body: wantBodyPost,
},
},
{
name: "successful POST with retries - request literal",
input: input{
req: func() *http.Request {
u, _ := url.Parse("http://example.com")
req := &http.Request{
Method: http.MethodPost,
URL: u,
Body: io.NopCloser(bytes.NewReader(wantBodyPost)),
}
return req
},
retryPolicy: RetryPolicy{
ShouldRetry: StandardShouldRetry,
Backoff: ExponentialBackoff(),
MaxRetries: 3,
MinDelay: 1 * time.Millisecond,
MaxDelay: 5 * time.Millisecond,
},
retries: 3,
err: errors.New("error"),
},
want: want{
statusCode: http.StatusOK,
body: wantBodyPost,
},
},
}

for _, test := range tests {
Expand Down

0 comments on commit ec25d3d

Please sign in to comment.