1package customizations 2 3import ( 4 "context" 5 "fmt" 6 "strings" 7 8 "github.com/aws/smithy-go/middleware" 9 smithyhttp "github.com/aws/smithy-go/transport/http" 10 11 "github.com/aws/aws-sdk-go-v2/aws" 12 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" 13 "github.com/aws/aws-sdk-go-v2/service/internal/s3shared" 14) 15 16// processOutpostIDMiddleware is special customization middleware to be applied for operations 17// CreateBucket, ListRegionalBuckets which must resolve endpoint to s3-outposts.{region}.amazonaws.com 18// with region as client region and signed by s3-control if an outpost id is provided. 19type processOutpostIDMiddleware struct { 20 // GetOutpostID points to a function that processes an input and returns an outpostID as string ptr, 21 // and bool indicating if outpostID is supported or set. 22 GetOutpostID func(interface{}) (*string, bool) 23 24 // UseDualStack indicates of dual stack endpoints should be used 25 UseDualstack bool 26} 27 28// ID returns the middleware ID. 29func (*processOutpostIDMiddleware) ID() string { return "S3Control:ProcessOutpostIDMiddleware" } 30 31// HandleSerialize adds a serialize step, this has to be before operation serializer and arn endpoint logic. 32// Ideally this step will be ahead of ARN customization for CreateBucket, ListRegionalBucket operation. 33func (m *processOutpostIDMiddleware) HandleSerialize( 34 ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, 35) ( 36 out middleware.SerializeOutput, metadata middleware.Metadata, err error, 37) { 38 // if host name is immutable, skip this customization 39 if smithyhttp.GetHostnameImmutable(ctx) { 40 return next.HandleSerialize(ctx, in) 41 } 42 43 // attempt to fetch an outpost id 44 outpostID, ok := m.GetOutpostID(in.Parameters) 45 if !ok { 46 return next.HandleSerialize(ctx, in) 47 } 48 49 // check if outpostID was not set or is empty 50 if outpostID == nil || len(strings.TrimSpace(*outpostID)) == 0 { 51 return next.HandleSerialize(ctx, in) 52 } 53 54 req, ok := in.Request.(*smithyhttp.Request) 55 if !ok { 56 return out, metadata, fmt.Errorf("unknown request type %T", req) 57 } 58 59 requestRegion := awsmiddleware.GetRegion(ctx) 60 61 // validate if fips 62 if s3shared.IsFIPS(requestRegion) { 63 return out, metadata, fmt.Errorf("unsupported fips region provided for outposts request") 64 } 65 // validate if dualstack 66 if m.UseDualstack { 67 return out, metadata, fmt.Errorf("dualstack is not supported for outposts request") 68 } 69 70 // if endpoint source is a custom endpoint source, do not modify host prefix. 71 // This is a requirement for s3 vpc interface endpoints. 72 if v := awsmiddleware.GetEndpointSource(ctx); v != aws.EndpointSourceCustom { 73 serviceEndpointLabel := "s3-outposts." 74 75 // set request url 76 req.URL.Host = serviceEndpointLabel + requestRegion + ".amazonaws.com" 77 } 78 79 // Disable endpoint host prefix for s3-control 80 ctx = smithyhttp.DisableEndpointHostPrefix(ctx, true) 81 82 // redirect signer 83 ctx = awsmiddleware.SetSigningName(ctx, "s3-outposts") 84 ctx = awsmiddleware.SetSigningRegion(ctx, requestRegion) 85 86 return next.HandleSerialize(ctx, in) 87} 88