github.com/aavshr/aws-sdk-go@v1.41.3/service/s3control/endpoint.go (about) 1 package s3control 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/aavshr/aws-sdk-go/aws" 8 awsarn "github.com/aavshr/aws-sdk-go/aws/arn" 9 "github.com/aavshr/aws-sdk-go/aws/request" 10 "github.com/aavshr/aws-sdk-go/internal/s3shared" 11 "github.com/aavshr/aws-sdk-go/internal/s3shared/arn" 12 ) 13 14 const ( 15 // outpost id header 16 outpostIDHeader = "x-amz-outpost-id" 17 18 // account id header 19 accountIDHeader = "x-amz-account-id" 20 ) 21 22 // Used by shapes with members decorated as endpoint ARN. 23 func parseEndpointARN(v string) (arn.Resource, error) { 24 return arn.ParseResource(v, resourceParser) 25 } 26 27 func resourceParser(a awsarn.ARN) (arn.Resource, error) { 28 resParts := arn.SplitResource(a.Resource) 29 switch resParts[0] { 30 case "outpost": 31 return arn.ParseOutpostARNResource(a, resParts[1:]) 32 default: 33 return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"} 34 } 35 } 36 37 func endpointHandler(req *request.Request) { 38 // For special case "CreateBucket" and "ListRegionalBuckets" operation 39 outpostIDEndpoint, ok := req.Params.(endpointOutpostIDGetter) 40 if ok && outpostIDEndpoint.hasOutpostID() { 41 outpostID, err := outpostIDEndpoint.getOutpostID() 42 if err != nil { 43 req.Error = fmt.Errorf("expected outpost ID to be supported, %v", err) 44 } 45 if len(strings.TrimSpace(outpostID)) == 0 { 46 return 47 } 48 updateRequestOutpostIDEndpoint(req) 49 return 50 } 51 52 endpoint, ok := req.Params.(endpointARNGetter) 53 if !ok || !endpoint.hasEndpointARN() { 54 return 55 } 56 57 resource, err := endpoint.getEndpointARN() 58 if err != nil { 59 req.Error = s3shared.NewInvalidARNError(nil, err) 60 return 61 } 62 63 // Add account-id header for the request if not present. 64 // SDK must always send the x-amz-account-id header for all requests 65 // where an accountId has been extracted from an ARN or the accountId field modeled as a header. 66 if h := req.HTTPRequest.Header.Get(accountIDHeader); len(h) == 0 { 67 req.HTTPRequest.Header.Add(accountIDHeader, resource.GetARN().AccountID) 68 } 69 70 switch tv := resource.(type) { 71 case arn.OutpostAccessPointARN: 72 // Add outpostID header 73 req.HTTPRequest.Header.Add(outpostIDHeader, tv.OutpostID) 74 75 // update arnable field to resource value 76 updatedInput, err := endpoint.updateArnableField(tv.AccessPointName) 77 if err != nil { 78 req.Error = err 79 return 80 } 81 82 // update request params to use modified ARN field value, if not nil 83 if updatedInput != nil { 84 req.Params = updatedInput 85 } 86 87 // update request for outpost access point endpoint 88 err = updateRequestOutpostAccessPointEndpoint(req, tv) 89 if err != nil { 90 req.Error = err 91 } 92 case arn.OutpostBucketARN: 93 // Add outpostID header 94 req.HTTPRequest.Header.Add(outpostIDHeader, tv.OutpostID) 95 96 // update arnable field to resource value 97 updatedInput, err := endpoint.updateArnableField(tv.BucketName) 98 if err != nil { 99 req.Error = err 100 return 101 } 102 103 // update request params to use modified ARN field value, if not nil 104 if updatedInput != nil { 105 req.Params = updatedInput 106 } 107 108 // update request for outpost bucket endpoint 109 err = updateRequestOutpostBucketEndpoint(req, tv) 110 if err != nil { 111 req.Error = err 112 } 113 default: 114 req.Error = s3shared.NewInvalidARNError(resource, nil) 115 } 116 } 117 118 // updateRequestOutpostIDEndpoint is special customization to be applied for operations 119 // CreateBucket, ListRegionalBuckets which must resolve endpoint to s3-outposts.{region}.amazonaws.com 120 // with region as client region and signed by s3-control if an outpost id is provided. 121 func updateRequestOutpostIDEndpoint(request *request.Request) { 122 cfgRegion := aws.StringValue(request.Config.Region) 123 124 if !hasCustomEndpoint(request) { 125 serviceEndpointLabel := "s3-outposts." 126 127 // request url 128 request.HTTPRequest.URL.Host = serviceEndpointLabel + cfgRegion + ".amazonaws.com" 129 130 // disable the host prefix for outpost access points 131 request.Config.DisableEndpointHostPrefix = aws.Bool(true) 132 } 133 134 // signer redirection 135 request.ClientInfo.SigningName = "s3-outposts" 136 request.ClientInfo.SigningRegion = cfgRegion 137 } 138 139 func updateRequestOutpostAccessPointEndpoint(req *request.Request, accessPoint arn.OutpostAccessPointARN) error { 140 // validate Outpost endpoint 141 if err := validateOutpostEndpoint(req, accessPoint); err != nil { 142 return err 143 } 144 145 // disable the host prefix for outpost access points 146 req.Config.DisableEndpointHostPrefix = aws.Bool(true) 147 148 if err := outpostAccessPointEndpointBuilder(accessPoint).build(req); err != nil { 149 return err 150 } 151 152 return nil 153 } 154 155 func updateRequestOutpostBucketEndpoint(req *request.Request, bucketResource arn.OutpostBucketARN) error { 156 // validate Outpost endpoint 157 if err := validateOutpostEndpoint(req, bucketResource); err != nil { 158 return err 159 } 160 161 // disable the host prefix for outpost bucket. 162 req.Config.DisableEndpointHostPrefix = aws.Bool(true) 163 164 if err := outpostBucketResourceEndpointBuilder(bucketResource).build(req); err != nil { 165 return err 166 } 167 168 return nil 169 } 170 171 // validate request resource for retrieving endpoint 172 func validateEndpointRequestResource(req *request.Request, resource arn.Resource) error { 173 resReq := s3shared.ResourceRequest{Request: req, Resource: resource} 174 175 if len(resReq.Request.ClientInfo.PartitionID) != 0 && resReq.IsCrossPartition() { 176 return s3shared.NewClientPartitionMismatchError(resource, 177 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 178 } 179 180 if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() { 181 return s3shared.NewClientRegionMismatchError(resource, 182 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 183 } 184 185 // Accelerate not supported 186 if aws.BoolValue(req.Config.S3UseAccelerate) { 187 return s3shared.NewClientConfiguredForAccelerateError(resource, 188 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 189 } 190 return nil 191 } 192 193 // validations for fetching outpost endpoint 194 func validateOutpostEndpoint(req *request.Request, resource arn.Resource) error { 195 resReq := s3shared.ResourceRequest{ 196 Request: req, 197 Resource: resource, 198 } 199 200 if err := validateEndpointRequestResource(req, resource); err != nil { 201 return err 202 } 203 204 // resource configured with FIPS as region is not supported by outposts 205 if resReq.UseFIPS() { 206 return s3shared.NewFIPSConfigurationError(resource, req.ClientInfo.PartitionID, 207 aws.StringValue(req.Config.Region), nil) 208 } 209 210 // DualStack not supported 211 if aws.BoolValue(req.Config.UseDualStack) { 212 return s3shared.NewClientConfiguredForDualStackError(resource, 213 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 214 } 215 return nil 216 }