Skip to content

Commit

Permalink
aws/request: Fix SDK's handling of endpoints ending in slash (#3926)
Browse files Browse the repository at this point in the history
Fixes the SDK's handling of endpoints that end in a slash (`/`) causing
signature validation errors due to Request.HTTPRequest.URL.Path not
matching what was sent in the request.
  • Loading branch information
jasdel authored May 27, 2021
1 parent d3c0287 commit 76fe6ef
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
### SDK Enhancements

### SDK Bugs
* `aws/request`: Fix handling of endpoints with trailing slashes
* Fixes the SDK's handling of endpoint URLs that contain a trailing slash when the API operation's modeled path is suffixed. Also ensures any endpoint URL query string is squashed consistently.
17 changes: 16 additions & 1 deletion aws/request/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,27 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
httpReq, _ := http.NewRequest(method, "", nil)

var err error
httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath)
httpReq.URL, err = url.Parse(clientInfo.Endpoint)
if err != nil {
httpReq.URL = &url.URL{}
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
}

if len(operation.HTTPPath) != 0 {
opHTTPPath := operation.HTTPPath
var opQueryString string
if idx := strings.Index(opHTTPPath, "?"); idx >= 0 {
opQueryString = opHTTPPath[idx+1:]
opHTTPPath = opHTTPPath[:idx]
}

if strings.HasSuffix(httpReq.URL.Path, "/") && strings.HasPrefix(opHTTPPath, "/") {
opHTTPPath = opHTTPPath[1:]
}
httpReq.URL.Path += opHTTPPath
httpReq.URL.RawQuery = opQueryString
}

r := &Request{
Config: cfg,
ClientInfo: clientInfo,
Expand Down
68 changes: 68 additions & 0 deletions aws/request/request_1_8_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,71 @@ func TestRequest_FollowPUTRedirects(t *testing.T) {
t.Errorf("expect %d endpoint hits, got %d", e, a)
}
}

func TestNewRequest_JoinEndpointWithOperationPathQuery(t *testing.T) {
cases := map[string]struct {
HTTPPath string
Endpoint *string
ExpectQuery string
ExpectPath string
}{
"no op HTTP Path": {
HTTPPath: "",
Endpoint: aws.String("https://foo.bar.aws/foo?bar=Baz"),
ExpectPath: "/foo",
ExpectQuery: "bar=Baz",
},
"no trailing slash": {
HTTPPath: "/",
Endpoint: aws.String("https://foo.bar.aws"),
ExpectPath: "/",
ExpectQuery: "",
},
"set query": {
HTTPPath: "/?Foo=bar",
Endpoint: aws.String("https://foo.bar.aws"),
ExpectPath: "/",
ExpectQuery: "Foo=bar",
},
"squash query": {
HTTPPath: "/?Foo=bar",
Endpoint: aws.String("https://foo.bar.aws/?bar=Foo"),
ExpectPath: "/",
ExpectQuery: "Foo=bar",
},
"trailing slash": {
HTTPPath: "/",
Endpoint: aws.String("https://foo.bar.aws/"),
ExpectPath: "/",
ExpectQuery: "",
},
"trailing slash set query": {
HTTPPath: "/?Foo=bar",
Endpoint: aws.String("https://foo.bar.aws/"),
ExpectPath: "/",
ExpectQuery: "Foo=bar",
},
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
client := awstesting.NewClient(&aws.Config{
Endpoint: c.Endpoint,
})

client.Handlers.Clear()
r := client.NewRequest(&request.Operation{
Name: "FooBar",
HTTPMethod: "GET",
HTTPPath: c.HTTPPath,
}, nil, nil)

if e, a := c.ExpectPath, r.HTTPRequest.URL.Path; e != a {
t.Errorf("expect %v path, got %v", e, a)
}
if e, a := c.ExpectQuery, r.HTTPRequest.URL.RawQuery; e != a {
t.Errorf("expect %v query, got %v", e, a)
}
})
}
}

0 comments on commit 76fe6ef

Please sign in to comment.