Skip to content

Commit 76fe6ef

Browse files
authored
aws/request: Fix SDK's handling of endpoints ending in slash (#3926)
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.
1 parent d3c0287 commit 76fe6ef

File tree

3 files changed

+86
-1
lines changed

3 files changed

+86
-1
lines changed

CHANGELOG_PENDING.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
### SDK Enhancements
44

55
### SDK Bugs
6+
* `aws/request`: Fix handling of endpoints with trailing slashes
7+
* 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.

aws/request/request.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,27 @@ func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
129129
httpReq, _ := http.NewRequest(method, "", nil)
130130

131131
var err error
132-
httpReq.URL, err = url.Parse(clientInfo.Endpoint + operation.HTTPPath)
132+
httpReq.URL, err = url.Parse(clientInfo.Endpoint)
133133
if err != nil {
134134
httpReq.URL = &url.URL{}
135135
err = awserr.New("InvalidEndpointURL", "invalid endpoint uri", err)
136136
}
137137

138+
if len(operation.HTTPPath) != 0 {
139+
opHTTPPath := operation.HTTPPath
140+
var opQueryString string
141+
if idx := strings.Index(opHTTPPath, "?"); idx >= 0 {
142+
opQueryString = opHTTPPath[idx+1:]
143+
opHTTPPath = opHTTPPath[:idx]
144+
}
145+
146+
if strings.HasSuffix(httpReq.URL.Path, "/") && strings.HasPrefix(opHTTPPath, "/") {
147+
opHTTPPath = opHTTPPath[1:]
148+
}
149+
httpReq.URL.Path += opHTTPPath
150+
httpReq.URL.RawQuery = opQueryString
151+
}
152+
138153
r := &Request{
139154
Config: cfg,
140155
ClientInfo: clientInfo,

aws/request/request_1_8_test.go

+68
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,71 @@ func TestRequest_FollowPUTRedirects(t *testing.T) {
8484
t.Errorf("expect %d endpoint hits, got %d", e, a)
8585
}
8686
}
87+
88+
func TestNewRequest_JoinEndpointWithOperationPathQuery(t *testing.T) {
89+
cases := map[string]struct {
90+
HTTPPath string
91+
Endpoint *string
92+
ExpectQuery string
93+
ExpectPath string
94+
}{
95+
"no op HTTP Path": {
96+
HTTPPath: "",
97+
Endpoint: aws.String("https://foo.bar.aws/foo?bar=Baz"),
98+
ExpectPath: "/foo",
99+
ExpectQuery: "bar=Baz",
100+
},
101+
"no trailing slash": {
102+
HTTPPath: "/",
103+
Endpoint: aws.String("https://foo.bar.aws"),
104+
ExpectPath: "/",
105+
ExpectQuery: "",
106+
},
107+
"set query": {
108+
HTTPPath: "/?Foo=bar",
109+
Endpoint: aws.String("https://foo.bar.aws"),
110+
ExpectPath: "/",
111+
ExpectQuery: "Foo=bar",
112+
},
113+
"squash query": {
114+
HTTPPath: "/?Foo=bar",
115+
Endpoint: aws.String("https://foo.bar.aws/?bar=Foo"),
116+
ExpectPath: "/",
117+
ExpectQuery: "Foo=bar",
118+
},
119+
"trailing slash": {
120+
HTTPPath: "/",
121+
Endpoint: aws.String("https://foo.bar.aws/"),
122+
ExpectPath: "/",
123+
ExpectQuery: "",
124+
},
125+
"trailing slash set query": {
126+
HTTPPath: "/?Foo=bar",
127+
Endpoint: aws.String("https://foo.bar.aws/"),
128+
ExpectPath: "/",
129+
ExpectQuery: "Foo=bar",
130+
},
131+
}
132+
133+
for name, c := range cases {
134+
t.Run(name, func(t *testing.T) {
135+
client := awstesting.NewClient(&aws.Config{
136+
Endpoint: c.Endpoint,
137+
})
138+
139+
client.Handlers.Clear()
140+
r := client.NewRequest(&request.Operation{
141+
Name: "FooBar",
142+
HTTPMethod: "GET",
143+
HTTPPath: c.HTTPPath,
144+
}, nil, nil)
145+
146+
if e, a := c.ExpectPath, r.HTTPRequest.URL.Path; e != a {
147+
t.Errorf("expect %v path, got %v", e, a)
148+
}
149+
if e, a := c.ExpectQuery, r.HTTPRequest.URL.RawQuery; e != a {
150+
t.Errorf("expect %v query, got %v", e, a)
151+
}
152+
})
153+
}
154+
}

0 commit comments

Comments
 (0)