Skip to content

Commit

Permalink
private : add support for httpChecksumRequired trait (#570)
Browse files Browse the repository at this point in the history
  • Loading branch information
skotambkar committed May 28, 2020
1 parent 40a22fc commit ef38358
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 113 deletions.
15 changes: 11 additions & 4 deletions service/s3/content_md5.go → private/checksum/content_md5.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
package s3
package checksum

import (
"crypto/md5"
"encoding/base64"
"io"

request "github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/awserr"
)

// contentMD5 computes and sets the HTTP Content-MD5 header for requests that
const contentMD5Header = "Content-Md5"

// AddBodyContentMD5Handler computes and sets the HTTP Content-MD5 header for requests that
// require it.
func contentMD5(r *request.Request) {
func AddBodyContentMD5Handler(r *aws.Request) {
// if Content-MD5 header is already present, return
if v := r.HTTPRequest.Header.Get(contentMD5Header); len(v) != 0 {
return
}

h := md5.New()

// hash the body. seek back to the first position after reading to reset
Expand Down
14 changes: 12 additions & 2 deletions private/model/api/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ type Operation struct {
Endpoint *EndpointTrait `json:"endpoint"`
HasEndpointARN bool `json:"-"`

IsEndpointDiscoveryOp bool `json:"endpointoperation"`
EndpointDiscovery *EndpointDiscovery `json:"endpointdiscovery"`
IsEndpointDiscoveryOp bool `json:"endpointoperation"`
EndpointDiscovery *EndpointDiscovery `json:"endpointdiscovery"`
IsHttpChecksumRequired bool `json:"httpChecksumRequired"`
}

// EndpointTrait provides the structure of the modeled enpdoint trait, and its
Expand Down Expand Up @@ -205,6 +206,15 @@ func (c *{{ .API.StructName }}) {{ $reqType }}(input {{ .InputRef.GoType }}) ({{
}
{{- end }}
{{ end -}}
{{- if .IsHttpChecksumRequired }}
{{- $_ := .API.AddSDKImport "private/checksum" }}
req.Handlers.Build.PushBackNamed(aws.NamedHandler{
Name: "contentMd5Handler",
Fn: checksum.AddBodyContentMD5Handler,
})
{{- end }}
return {{ $reqType }}{Request: req, Input: input, Copy: c.{{ $reqType }} }
}
Expand Down
330 changes: 330 additions & 0 deletions service/s3/content_md5_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,330 @@
package s3_test

import (
"crypto/md5"
"encoding/base64"
"io/ioutil"
"testing"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/internal/awstesting/unit"
"github.com/aws/aws-sdk-go-v2/service/s3"
)

func assertMD5(t *testing.T, req *aws.Request) {
err := req.Build()
if err != nil {
t.Errorf("expected no error, but received %v", err)
}

b, _ := ioutil.ReadAll(req.HTTPRequest.Body)
out := md5.Sum(b)
if len(b) == 0 {
t.Error("expected non-empty value")
}
if a := req.HTTPRequest.Header.Get("Content-MD5"); len(a) == 0 {
t.Fatal("Expected Content-MD5 header to be present in the operation request, was not")
} else if e := base64.StdEncoding.EncodeToString(out[:]); e != a {
t.Errorf("expected %s, but received %s", e, a)
}
}

func TestMD5InPutBucketCors(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketCorsRequest(&s3.PutBucketCorsInput{
Bucket: aws.String("bucketname"),
CORSConfiguration: &s3.CORSConfiguration{
CORSRules: []s3.CORSRule{
{
AllowedMethods: []string{"GET"},
AllowedOrigins: []string{"*"},
},
},
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketLifecycle(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketLifecycleRequest(&s3.PutBucketLifecycleInput{
Bucket: aws.String("bucketname"),
LifecycleConfiguration: &s3.LifecycleConfiguration{
Rules: []s3.Rule{
{
ID: aws.String("ID"),
Prefix: aws.String("Prefix"),
Status: s3.ExpirationStatusEnabled,
},
},
},
})
assertMD5(t, req.Request)
}

func TestMD5InPutBucketPolicy(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketPolicyRequest(&s3.PutBucketPolicyInput{
Bucket: aws.String("bucketname"),
Policy: aws.String("{}"),
})
assertMD5(t, req.Request)
}

func TestMD5InPutBucketTagging(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketTaggingRequest(&s3.PutBucketTaggingInput{
Bucket: aws.String("bucketname"),
Tagging: &s3.Tagging{
TagSet: []s3.Tag{
{Key: aws.String("KEY"), Value: aws.String("VALUE")},
},
},
})
assertMD5(t, req.Request)
}

func TestMD5InDeleteObjects(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.DeleteObjectsRequest(&s3.DeleteObjectsInput{
Bucket: aws.String("bucketname"),
Delete: &s3.Delete{
Objects: []s3.ObjectIdentifier{
{Key: aws.String("key")},
},
},
})
assertMD5(t, req.Request)
}

func TestMD5InPutBucketLifecycleConfiguration(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketLifecycleConfigurationRequest(&s3.PutBucketLifecycleConfigurationInput{
Bucket: aws.String("bucketname"),
LifecycleConfiguration: &s3.BucketLifecycleConfiguration{
Rules: []s3.LifecycleRule{
{Prefix: aws.String("prefix"), Status: s3.ExpirationStatusEnabled},
},
},
})
assertMD5(t, req.Request)
}

func TestMD5InPutBucketReplication(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketReplicationRequest(&s3.PutBucketReplicationInput{
Bucket: aws.String("bucketname"),
ReplicationConfiguration: &s3.ReplicationConfiguration{
Role: aws.String("Role"),
Rules: []s3.ReplicationRule{
{
Destination: &s3.Destination{
Bucket: aws.String("mock bucket"),
},
},
},
},
Token: aws.String("token"),
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketAcl(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketAclRequest(&s3.PutBucketAclInput{
Bucket: aws.String("bucketname"),
AccessControlPolicy: &s3.AccessControlPolicy{
Grants: []s3.Grant{{
Grantee: &s3.Grantee{
ID: aws.String("mock id"),
Type: s3.Type("type"),
},
Permission: s3.PermissionFullControl,
}},
Owner: &s3.Owner{
DisplayName: aws.String("mock name"),
},
},
})
assertMD5(t, req.Request)
}

func TestMD5InPutBucketEncryption(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketEncryptionRequest(&s3.PutBucketEncryptionInput{
Bucket: aws.String("bucketname"),
ServerSideEncryptionConfiguration: &s3.ServerSideEncryptionConfiguration{
Rules: []s3.ServerSideEncryptionRule{
{
ApplyServerSideEncryptionByDefault: &s3.ServerSideEncryptionByDefault{
KMSMasterKeyID: aws.String("mock KMS master key id"),
SSEAlgorithm: "mock SSE algorithm",
},
},
},
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketLogging(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketLoggingRequest(&s3.PutBucketLoggingInput{
Bucket: aws.String("bucket name"),
BucketLoggingStatus: &s3.BucketLoggingStatus{LoggingEnabled: &s3.LoggingEnabled{
TargetBucket: aws.String("target bucket"),
TargetPrefix: aws.String("target prefix"),
}},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketNotification(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketNotificationRequest(&s3.PutBucketNotificationInput{
Bucket: aws.String("bucket name"),
NotificationConfiguration: &s3.NotificationConfigurationDeprecated{
TopicConfiguration: &s3.TopicConfigurationDeprecated{
Id: aws.String("id"),
},
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketRequestPayment(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketRequestPaymentRequest(&s3.PutBucketRequestPaymentInput{
Bucket: aws.String("bucketname"),
RequestPaymentConfiguration: &s3.RequestPaymentConfiguration{
Payer: s3.Payer("payer"),
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketVersioning(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketVersioningRequest(&s3.PutBucketVersioningInput{
Bucket: aws.String("bucketname"),
VersioningConfiguration: &s3.VersioningConfiguration{
MFADelete: s3.MFADeleteDisabled,
Status: s3.BucketVersioningStatusSuspended,
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutBucketWebsite(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutBucketWebsiteRequest(&s3.PutBucketWebsiteInput{
Bucket: aws.String("bucket name"),
WebsiteConfiguration: &s3.WebsiteConfiguration{
ErrorDocument: &s3.ErrorDocument{
Key: aws.String("error"),
},
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutObjectLegalHold(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutObjectLegalHoldRequest(&s3.PutObjectLegalHoldInput{
Bucket: aws.String("bucketname"),
Key: aws.String("key"),
LegalHold: &s3.ObjectLockLegalHold{
Status: s3.ObjectLockLegalHoldStatusOff,
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutObjectRetention(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutObjectRetentionRequest(&s3.PutObjectRetentionInput{
Bucket: aws.String("bucket name"),
BypassGovernanceRetention: nil,
Key: aws.String("key"),
Retention: &s3.ObjectLockRetention{
Mode: s3.ObjectLockRetentionMode("mode"),
},
VersionId: nil,
})

assertMD5(t, req.Request)
}

func TestMD5InPutObjectLockConfiguration(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutObjectLockConfigurationRequest(&s3.PutObjectLockConfigurationInput{
Bucket: aws.String("bucket name"),
ObjectLockConfiguration: &s3.ObjectLockConfiguration{
ObjectLockEnabled: s3.ObjectLockEnabledEnabled,
},
})

assertMD5(t, req.Request)
}

func TestMD5InPutObjectAcl(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutObjectAclRequest(&s3.PutObjectAclInput{
AccessControlPolicy: &s3.AccessControlPolicy{
Grants: []s3.Grant{{
Grantee: &s3.Grantee{
ID: aws.String("mock id"),
Type: s3.Type("type"),
},
Permission: s3.PermissionFullControl,
}},
Owner: &s3.Owner{
DisplayName: aws.String("mock name"),
},
},
Bucket: aws.String("bucket name"),
Key: aws.String("key"),
})

assertMD5(t, req.Request)
}

func TestMD5InPutObjectTagging(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutObjectTaggingRequest(&s3.PutObjectTaggingInput{
Bucket: aws.String("bucket name"),
Key: aws.String("key"),
Tagging: &s3.Tagging{TagSet: []s3.Tag{
{
Key: aws.String("key"),
Value: aws.String("value"),
},
}},
})

assertMD5(t, req.Request)
}

func TestMD5InPutPublicAccessBlock(t *testing.T) {
svc := s3.New(unit.Config())
req := svc.PutPublicAccessBlockRequest(&s3.PutPublicAccessBlockInput{
Bucket: aws.String("bucket name"),
PublicAccessBlockConfiguration: &s3.PublicAccessBlockConfiguration{
BlockPublicAcls: aws.Bool(true),
BlockPublicPolicy: aws.Bool(true),
IgnorePublicAcls: aws.Bool(true),
RestrictPublicBuckets: aws.Bool(true),
},
})

assertMD5(t, req.Request)
}
Loading

0 comments on commit ef38358

Please sign in to comment.