diff --git a/private/signer/v4/v4.go b/private/signer/v4/v4.go index eb237312121..47658005629 100644 --- a/private/signer/v4/v4.go +++ b/private/signer/v4/v4.go @@ -337,7 +337,7 @@ func (v4 *signer) buildCanonicalHeaders(r rule, header http.Header) { } } - v4.canonicalHeaders = strings.Join(headerValues, "\n") + v4.canonicalHeaders = strings.Join(stripExcessSpaces(headerValues), "\n") } func (v4 *signer) buildCanonicalString() { @@ -443,3 +443,23 @@ func makeSha256Reader(reader io.ReadSeeker) []byte { io.Copy(hash, reader) return hash.Sum(nil) } + +func stripExcessSpaces(headerVals []string) []string { + vals := make([]string, len(headerVals)) + for i, str := range headerVals { + stripped := "" + found := false + str = strings.TrimSpace(str) + for _, c := range str { + if !found && c == ' ' { + stripped += string(c) + found = true + } else if c != ' ' { + stripped += string(c) + found = false + } + } + vals[i] = stripped + } + return vals +} diff --git a/private/signer/v4/v4_test.go b/private/signer/v4/v4_test.go index c22e5ff38d8..604d6423582 100644 --- a/private/signer/v4/v4_test.go +++ b/private/signer/v4/v4_test.go @@ -290,6 +290,35 @@ func TestResignRequestExpiredRequest(t *testing.T) { assert.NotEqual(t, querySig, r.HTTPRequest.Header.Get("Authorization")) } +func TestStripExcessHeaders(t *testing.T) { + vals := []string{ + "123", + "1 2 3", + " 1 2 3", + "1 2 3", + "1 23", + "1 2 3", + "1 2 ", + " 1 2 ", + } + + expected := []string{ + "123", + "1 2 3", + "1 2 3", + "1 2 3", + "1 23", + "1 2 3", + "1 2", + "1 2", + } + + newVals := stripExcessSpaces(vals) + for i := 0; i < len(newVals); i++ { + assert.Equal(t, newVals[i], expected[i]) + } +} + func BenchmarkPresignRequest(b *testing.B) { signer := buildSigner("dynamodb", "us-east-1", time.Now(), 300*time.Second, "{}") for i := 0; i < b.N; i++ {