"X-Amz-Server-Side-Encryption-Customer-Key": struct{}{},
"X-Amz-Server-Side-Encryption-Customer-Key-Md5": struct{}{},
"X-Amz-Storage-Class": struct{}{},
+ "X-Amz-Tagging": struct{}{},
"X-Amz-Website-Redirect-Location": struct{}{},
"X-Amz-Content-Sha256": struct{}{},
},
// http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
DisableURIPathEscaping bool
- // Disales the automatical setting of the HTTP request's Body field with the
+ // Disables the automatical setting of the HTTP request's Body field with the
// io.ReadSeeker passed in to the signer. This is useful if you're using a
// custom wrapper around the body for the io.ReadSeeker and want to preserve
// the Body value on the Request.Body.
// If the credentials of the request's config are set to
// credentials.AnonymousCredentials the request will not be signed.
func SignSDKRequest(req *request.Request) {
- signSDKRequestWithCurrTime(req, time.Now)
+ SignSDKRequestWithCurrentTime(req, time.Now)
}
// BuildNamedHandler will build a generic handler for signing.
return request.NamedHandler{
Name: name,
Fn: func(req *request.Request) {
- signSDKRequestWithCurrTime(req, time.Now, opts...)
+ SignSDKRequestWithCurrentTime(req, time.Now, opts...)
},
}
}
-func signSDKRequestWithCurrTime(req *request.Request, curTimeFn func() time.Time, opts ...func(*Signer)) {
+// SignSDKRequestWithCurrentTime will sign the SDK's request using the time
+// function passed in. Behaves the same as SignSDKRequest with the exception
+// the request is signed with the value returned by the current time function.
+func SignSDKRequestWithCurrentTime(req *request.Request, curTimeFn func() time.Time, opts ...func(*Signer)) {
// If the request does not need to be signed ignore the signing of the
// request if the AnonymousCredentials object is used.
if req.Config.Credentials == credentials.AnonymousCredentials {
opt(v4)
}
- signingTime := req.Time
- if !req.LastSignedAt.IsZero() {
- signingTime = req.LastSignedAt
- }
-
+ curTime := curTimeFn()
signedHeaders, err := v4.signWithBody(req.HTTPRequest, req.GetBody(),
- name, region, req.ExpireTime, req.ExpireTime > 0, signingTime,
+ name, region, req.ExpireTime, req.ExpireTime > 0, curTime,
)
if err != nil {
req.Error = err
}
req.SignedHeaderVals = signedHeaders
- req.LastSignedAt = curTimeFn()
+ req.LastSignedAt = curTime
}
const logSignInfoMsg = `DEBUG: Request Signature:
if !aws.IsReaderSeekable(ctx.Body) {
return fmt.Errorf("cannot use unseekable request body %T, for signed request with body", ctx.Body)
}
- hash = hex.EncodeToString(makeSha256Reader(ctx.Body))
+ hashBytes, err := makeSha256Reader(ctx.Body)
+ if err != nil {
+ return err
+ }
+ hash = hex.EncodeToString(hashBytes)
}
if includeSHA256Header {
return hash.Sum(nil)
}
-func makeSha256Reader(reader io.ReadSeeker) []byte {
+func makeSha256Reader(reader io.ReadSeeker) (hashBytes []byte, err error) {
hash := sha256.New()
- start, _ := reader.Seek(0, sdkio.SeekCurrent)
- defer reader.Seek(start, sdkio.SeekStart)
+ start, err := reader.Seek(0, sdkio.SeekCurrent)
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ // ensure error is return if unable to seek back to start of payload.
+ _, err = reader.Seek(start, sdkio.SeekStart)
+ }()
- io.Copy(hash, reader)
- return hash.Sum(nil)
+ // Use CopyN to avoid allocating the 32KB buffer in io.Copy for bodies
+ // smaller than 32KB. Fall back to io.Copy if we fail to determine the size.
+ size, err := aws.SeekerLen(reader)
+ if err != nil {
+ io.Copy(hash, reader)
+ } else {
+ io.CopyN(hash, reader, size)
+ }
+
+ return hash.Sum(nil), nil
}
const doubleSpace = " "
// stripExcessSpaces will rewrite the passed in slice's string values to not
-// contain muliple side-by-side spaces.
+// contain multiple side-by-side spaces.
func stripExcessSpaces(vals []string) {
var j, k, l, m, spaces int
for i, str := range vals {