Skip to content

Commit fd01a01

Browse files
authored
aws/defaults: Fix request metadata headers causing signature errors (#537)
Fixes the SDK's adding the request metadata headers in the wrong location within the request handler stack. This created a situation where a request that was retried would sign the new attempt using the old value of the header. The header value would then be changed before sending the request. This moves the request invocation id to only occur during build, maintaining its value across all requests attempts. Also moves request retry metadata header to be before sign, and after build. This ensures that a new value for each attempt can be set, and included in each request attempt. Fix #533 Fix #521
1 parent 66c29ca commit fd01a01

File tree

4 files changed

+52
-6
lines changed

4 files changed

+52
-6
lines changed

CHANGELOG_PENDING.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ SDK Bugs
3939
* `internal/sdk`: Fix SDK's UUID utility to handle partial read ([#536](https://github.com/aws/aws-sdk-go-v2/pull/536))
4040
* Fixes the SDK's UUID utility to correctly handle partial reads from its crypto rand source. This error was sometimes causing the SDK's InvocationID value to fail to be obtained, due to a partial read from crypto.Rand.
4141
* Fix [#534](https://github.com/aws/aws-sdk-go-v2/issues/534)
42+
* `aws/defaults`: Fix request metadata headers causing signature errors ([#536](https://github.com/aws/aws-sdk-go-v2/pull/536))
43+
* Fixes the SDK's adding the request metadata headers in the wrong location within the request handler stack. This created a situation where a request that was retried would sign the new attempt using the old value of the header. The header value would then be changed before sending the request.
44+
* Fix [#533](https://github.com/aws/aws-sdk-go-v2/issues/533)
45+
* Fix [#521](https://github.com/aws/aws-sdk-go-v2/issues/521)

aws/defaults/defaults.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ func Handlers() aws.Handlers {
7070
handlers.Validate.AfterEachFn = aws.HandlerListStopOnError
7171
handlers.Build.PushBackNamed(SDKVersionUserAgentHandler)
7272
handlers.Build.PushBackNamed(AddHostExecEnvUserAgentHander)
73+
handlers.Build.PushFrontNamed(RequestInvocationIDHeaderHandler)
7374
handlers.Build.AfterEachFn = aws.HandlerListStopOnError
7475
handlers.Sign.PushBackNamed(BuildContentLengthHandler)
75-
handlers.Send.PushFrontNamed(RequestInvocationIDHeaderHandler)
76-
handlers.Send.PushFrontNamed(RetryMetricHeaderHandler)
76+
handlers.Sign.PushFrontNamed(RetryMetricHeaderHandler)
7777
handlers.Send.PushBackNamed(ValidateReqSigHandler)
7878
handlers.Send.PushBackNamed(SendHandler)
7979
handlers.Send.PushBackNamed(AttemptClockSkewHandler)

aws/defaults/handlers.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,12 @@ var ValidateResponseHandler = aws.NamedHandler{
190190
var RequestInvocationIDHeaderHandler = aws.NamedHandler{
191191
Name: "core.RequestInvocationIDHeaderHandler",
192192
Fn: func(r *aws.Request) {
193+
if r.ExpireTime != 0 {
194+
// ExpireTime set implies a presigned URL which will not have the
195+
// header applied.
196+
return
197+
}
198+
193199
const invocationIDHeader = "amz-sdk-invocation-id"
194200
r.HTTPRequest.Header.Set(invocationIDHeader, r.InvocationID)
195201
}}
@@ -199,6 +205,12 @@ var RequestInvocationIDHeaderHandler = aws.NamedHandler{
199205
var RetryMetricHeaderHandler = aws.NamedHandler{
200206
Name: "core.RetryMetricHeaderHandler",
201207
Fn: func(r *aws.Request) {
208+
if r.ExpireTime != 0 {
209+
// ExpireTime set implies a presigned URL which will not have the
210+
// header applied.
211+
return
212+
}
213+
202214
const retryMetricHeader = "amz-sdk-request"
203215
var parts []string
204216

aws/defaults/handlers_test.go

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"io"
89
"io/ioutil"
910
"net/http"
1011
"net/http/httptest"
@@ -333,16 +334,45 @@ func TestSendHandler_HEADNoBody(t *testing.T) {
333334

334335
func TestRequestInvocationIDHeaderHandler(t *testing.T) {
335336
cfg := unit.Config()
336-
r := aws.New(cfg, aws.Metadata{}, cfg.Handlers, aws.NoOpRetryer{}, &aws.Operation{},
337+
cfg.Handlers.Send.Clear()
338+
339+
var invokeID string
340+
cfg.Handlers.Build.PushBack(func(r *aws.Request) {
341+
invokeID = r.InvocationID
342+
if len(invokeID) == 0 {
343+
t.Fatalf("expect non-empty invocation id")
344+
}
345+
})
346+
cfg.Handlers.Send.PushBack(func(r *aws.Request) {
347+
if e, a := invokeID, r.InvocationID; e != a {
348+
t.Errorf("expect %v invoke ID, got %v", e, a)
349+
}
350+
r.Error = &aws.RequestSendError{Err: io.ErrUnexpectedEOF}
351+
})
352+
retryer := retry.NewStandard(func(o *retry.StandardOptions) {
353+
o.MaxAttempts = 3
354+
})
355+
r := aws.New(cfg, aws.Metadata{}, cfg.Handlers, retryer, &aws.Operation{},
337356
&struct{}{}, struct{}{})
338357

339358
if len(r.InvocationID) == 0 {
340359
t.Fatalf("expect invocation id, got none")
341360
}
342361

343-
defaults.RequestInvocationIDHeaderHandler.Fn(r)
344-
if r.Error != nil {
345-
t.Fatalf("expect no error, got %v", r.Error)
362+
err := r.Send()
363+
if err == nil {
364+
t.Fatalf("expect error got on")
365+
}
366+
var maxErr *aws.MaxAttemptsError
367+
if !errors.As(err, &maxErr) {
368+
t.Fatalf("expect max errors, got %v", err)
369+
} else {
370+
if e, a := 3, maxErr.Attempt; e != a {
371+
t.Errorf("expect %v attempts, got %v", e, a)
372+
}
373+
}
374+
if len(invokeID) == 0 {
375+
t.Fatalf("expect non-empty invocation id")
346376
}
347377

348378
if e, a := r.InvocationID, r.HTTPRequest.Header.Get("amz-sdk-invocation-id"); e != a {

0 commit comments

Comments
 (0)