From 28b1fd28879898d7330b3765103169c3d2900847 Mon Sep 17 00:00:00 2001
From: Jason Del Ponte <961963+jasdel@users.noreply.github.com>
Date: Wed, 26 Jan 2022 12:26:53 -0800
Subject: [PATCH] aws/config: Update Request Send to always ensure HTTPResponse
 is not nil (#4256)

Updates SDK Request.Send to always ensure HTTPResponse member is not
nil, and its Header and Body fields are not nil as well.

Fixes #4211
---
 CHANGELOG_PENDING.md        |  2 ++
 aws/request/request.go      |  9 +++++++++
 aws/request/request_test.go | 31 +++++++++++++++++++++++++++++++
 3 files changed, 42 insertions(+)

diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md
index 8a1927a39ca..d5e775f28b3 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 fb0a68fce3e..636d9ec943b 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 024d1ba1672..1d271f480d2 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
 }