diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index 8a1927a39c..d5e775f28b 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -3,3 +3,5 @@ ### SDK Enhancements ### SDK Bugs +* `aws/request`: Update Request Send to always ensure Request.HTTPResponse is populated. + * Fixes [#4211](https://github.com/aws/aws-sdk-go/issues/4211) diff --git a/aws/request/request.go b/aws/request/request.go index fb0a68fce3..636d9ec943 100644 --- a/aws/request/request.go +++ b/aws/request/request.go @@ -4,6 +4,7 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "net/http" "net/url" "reflect" @@ -525,6 +526,14 @@ func (r *Request) GetBody() io.ReadSeeker { // Send will not close the request.Request's body. func (r *Request) Send() error { defer func() { + // Ensure a non-nil HTTPResponse parameter is set to ensure handlers + // checking for HTTPResponse values, don't fail. + if r.HTTPResponse == nil { + r.HTTPResponse = &http.Response{ + Header: http.Header{}, + Body: ioutil.NopCloser(&bytes.Buffer{}), + } + } // Regardless of success or failure of the request trigger the Complete // request handlers. r.Handlers.Complete.Run(r) diff --git a/aws/request/request_test.go b/aws/request/request_test.go index 024d1ba167..1d271f480d 100644 --- a/aws/request/request_test.go +++ b/aws/request/request_test.go @@ -1257,6 +1257,37 @@ func TestRequestMarshaledEndpointWithNonDefaultPort(t *testing.T) { } } +func TestRequestCompleteWithoutHTTPResponse(t *testing.T) { + s := awstesting.NewClient(aws.NewConfig().WithRegion("mock-region")) + r := s.NewRequest(&request.Operation{ + Name: "FooBar", + HTTPMethod: "GET", + HTTPPath: "/", + }, nil, nil) + r.Handlers.Sign.Clear() + r.Handlers.Sign.PushFront(func(r *request.Request) { + r.Error = fmt.Errorf("failed") + }) + r.Handlers.Complete.PushBack(func(r *request.Request) { + if r.HTTPResponse == nil { + t.Fatalf("expect HTTPResponse not to be nil") + } + if r.HTTPResponse.Header == nil { + t.Fatalf("expect HTTPResponse.Header not to be nil") + } + if r.HTTPResponse.Body == nil { + t.Fatalf("expect HTTPResponse.Body not to be nil") + } + }) + err := r.Send() + if err == nil { + t.Fatalf("expect error, got none") + } + if e, a := "failed", err.Error(); !strings.Contains(a, e) { + t.Errorf("expect %v error in %v", e, a) + } +} + type stubSeekFail struct { Err error }