72e35af39f
Signed-off-by: Taylor Skinner <tskinn12@gmail.com> add some comments Signed-off-by: Taylor Skinner <tskinn12@gmail.com> update readmes make test runnable Signed-off-by: Taylor Skinner <tskinn12@gmail.com> make test squash! add dynamo add glide.lock format imports gofmt update glide.lock fixes for review golint clean up and reorganize tests add dynamodb integration test remove default region. clean up tests. consistent docs forgot the region is required DRY make validate update readme and commit dependencies
98 lines
2.2 KiB
Go
98 lines
2.2 KiB
Go
package dynamodb
|
|
|
|
import (
|
|
"bytes"
|
|
"hash/crc32"
|
|
"io"
|
|
"io/ioutil"
|
|
"math"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
|
"github.com/aws/aws-sdk-go/aws/client"
|
|
"github.com/aws/aws-sdk-go/aws/request"
|
|
)
|
|
|
|
type retryer struct {
|
|
client.DefaultRetryer
|
|
}
|
|
|
|
func (d retryer) RetryRules(r *request.Request) time.Duration {
|
|
delay := time.Duration(math.Pow(2, float64(r.RetryCount))) * 50
|
|
return delay * time.Millisecond
|
|
}
|
|
|
|
func init() {
|
|
initClient = func(c *client.Client) {
|
|
r := retryer{}
|
|
if c.Config.MaxRetries == nil || aws.IntValue(c.Config.MaxRetries) == aws.UseServiceDefaultRetries {
|
|
r.NumMaxRetries = 10
|
|
} else {
|
|
r.NumMaxRetries = *c.Config.MaxRetries
|
|
}
|
|
c.Retryer = r
|
|
|
|
c.Handlers.Build.PushBack(disableCompression)
|
|
c.Handlers.Unmarshal.PushFront(validateCRC32)
|
|
}
|
|
}
|
|
|
|
func drainBody(b io.ReadCloser, length int64) (out *bytes.Buffer, err error) {
|
|
if length < 0 {
|
|
length = 0
|
|
}
|
|
buf := bytes.NewBuffer(make([]byte, 0, length))
|
|
|
|
if _, err = buf.ReadFrom(b); err != nil {
|
|
return nil, err
|
|
}
|
|
if err = b.Close(); err != nil {
|
|
return nil, err
|
|
}
|
|
return buf, nil
|
|
}
|
|
|
|
func disableCompression(r *request.Request) {
|
|
r.HTTPRequest.Header.Set("Accept-Encoding", "identity")
|
|
}
|
|
|
|
func validateCRC32(r *request.Request) {
|
|
if r.Error != nil {
|
|
return // already have an error, no need to verify CRC
|
|
}
|
|
|
|
// Checksum validation is off, skip
|
|
if aws.BoolValue(r.Config.DisableComputeChecksums) {
|
|
return
|
|
}
|
|
|
|
// Try to get CRC from response
|
|
header := r.HTTPResponse.Header.Get("X-Amz-Crc32")
|
|
if header == "" {
|
|
return // No header, skip
|
|
}
|
|
|
|
expected, err := strconv.ParseUint(header, 10, 32)
|
|
if err != nil {
|
|
return // Could not determine CRC value, skip
|
|
}
|
|
|
|
buf, err := drainBody(r.HTTPResponse.Body, r.HTTPResponse.ContentLength)
|
|
if err != nil { // failed to read the response body, skip
|
|
return
|
|
}
|
|
|
|
// Reset body for subsequent reads
|
|
r.HTTPResponse.Body = ioutil.NopCloser(bytes.NewReader(buf.Bytes()))
|
|
|
|
// Compute the CRC checksum
|
|
crc := crc32.ChecksumIEEE(buf.Bytes())
|
|
|
|
if crc != uint32(expected) {
|
|
// CRC does not match, set a retryable error
|
|
r.Retryable = aws.Bool(true)
|
|
r.Error = awserr.New("CRC32CheckFailed", "CRC32 integrity check failed", nil)
|
|
}
|
|
}
|