github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/endpoint.go (about) 1 package s3 2 3 import ( 4 "fmt" 5 "github.com/aavshr/aws-sdk-go/aws/awserr" 6 "net/url" 7 "strings" 8 9 "github.com/aavshr/aws-sdk-go/aws" 10 awsarn "github.com/aavshr/aws-sdk-go/aws/arn" 11 "github.com/aavshr/aws-sdk-go/aws/request" 12 "github.com/aavshr/aws-sdk-go/internal/s3shared" 13 "github.com/aavshr/aws-sdk-go/internal/s3shared/arn" 14 ) 15 16 const ( 17 s3Namespace = "s3" 18 s3AccessPointNamespace = "s3-accesspoint" 19 s3ObjectsLambdaNamespace = "s3-object-lambda" 20 s3OutpostsNamespace = "s3-outposts" 21 ) 22 23 // Used by shapes with members decorated as endpoint ARN. 24 func parseEndpointARN(v string) (arn.Resource, error) { 25 return arn.ParseResource(v, accessPointResourceParser) 26 } 27 28 func accessPointResourceParser(a awsarn.ARN) (arn.Resource, error) { 29 resParts := arn.SplitResource(a.Resource) 30 switch resParts[0] { 31 case "accesspoint": 32 switch a.Service { 33 case s3Namespace: 34 return arn.ParseAccessPointResource(a, resParts[1:]) 35 case s3ObjectsLambdaNamespace: 36 return parseS3ObjectLambdaAccessPointResource(a, resParts) 37 default: 38 return arn.AccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s or %s", s3Namespace, s3ObjectsLambdaNamespace)} 39 } 40 case "outpost": 41 if a.Service != "s3-outposts" { 42 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3-outposts"} 43 } 44 return parseOutpostAccessPointResource(a, resParts[1:]) 45 default: 46 return nil, arn.InvalidARNError{ARN: a, Reason: "unknown resource type"} 47 } 48 } 49 50 // parseOutpostAccessPointResource attempts to parse the ARNs resource as an 51 // outpost access-point resource. 52 // 53 // Supported Outpost AccessPoint ARN format: 54 // - ARN format: arn:{partition}:s3-outposts:{region}:{accountId}:outpost/{outpostId}/accesspoint/{accesspointName} 55 // - example: arn:aws:s3-outposts:us-west-2:012345678901:outpost/op-1234567890123456/accesspoint/myaccesspoint 56 // 57 func parseOutpostAccessPointResource(a awsarn.ARN, resParts []string) (arn.OutpostAccessPointARN, error) { 58 // outpost accesspoint arn is only valid if service is s3-outposts 59 if a.Service != "s3-outposts" { 60 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "service is not s3-outposts"} 61 } 62 63 if len(resParts) == 0 { 64 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "outpost resource-id not set"} 65 } 66 67 if len(resParts) < 3 { 68 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ 69 ARN: a, Reason: "access-point resource not set in Outpost ARN", 70 } 71 } 72 73 resID := strings.TrimSpace(resParts[0]) 74 if len(resID) == 0 { 75 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "outpost resource-id not set"} 76 } 77 78 var outpostAccessPointARN = arn.OutpostAccessPointARN{} 79 switch resParts[1] { 80 case "accesspoint": 81 accessPointARN, err := arn.ParseAccessPointResource(a, resParts[2:]) 82 if err != nil { 83 return arn.OutpostAccessPointARN{}, err 84 } 85 // set access-point arn 86 outpostAccessPointARN.AccessPointARN = accessPointARN 87 default: 88 return arn.OutpostAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: "access-point resource not set in Outpost ARN"} 89 } 90 91 // set outpost id 92 outpostAccessPointARN.OutpostID = resID 93 return outpostAccessPointARN, nil 94 } 95 96 func parseS3ObjectLambdaAccessPointResource(a awsarn.ARN, resParts []string) (arn.S3ObjectLambdaAccessPointARN, error) { 97 if a.Service != s3ObjectsLambdaNamespace { 98 return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("service is not %s", s3ObjectsLambdaNamespace)} 99 } 100 101 accessPointARN, err := arn.ParseAccessPointResource(a, resParts[1:]) 102 if err != nil { 103 return arn.S3ObjectLambdaAccessPointARN{}, err 104 } 105 106 if len(accessPointARN.Region) == 0 { 107 return arn.S3ObjectLambdaAccessPointARN{}, arn.InvalidARNError{ARN: a, Reason: fmt.Sprintf("%s region not set", s3ObjectsLambdaNamespace)} 108 } 109 110 return arn.S3ObjectLambdaAccessPointARN{ 111 AccessPointARN: accessPointARN, 112 }, nil 113 } 114 115 func endpointHandler(req *request.Request) { 116 endpoint, ok := req.Params.(endpointARNGetter) 117 if !ok || !endpoint.hasEndpointARN() { 118 updateBucketEndpointFromParams(req) 119 return 120 } 121 122 resource, err := endpoint.getEndpointARN() 123 if err != nil { 124 req.Error = s3shared.NewInvalidARNError(nil, err) 125 return 126 } 127 128 resReq := s3shared.ResourceRequest{ 129 Resource: resource, 130 Request: req, 131 } 132 133 if len(resReq.Request.ClientInfo.PartitionID) != 0 && resReq.IsCrossPartition() { 134 req.Error = s3shared.NewClientPartitionMismatchError(resource, 135 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 136 return 137 } 138 139 if !resReq.AllowCrossRegion() && resReq.IsCrossRegion() { 140 req.Error = s3shared.NewClientRegionMismatchError(resource, 141 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 142 return 143 } 144 145 switch tv := resource.(type) { 146 case arn.AccessPointARN: 147 err = updateRequestAccessPointEndpoint(req, tv) 148 if err != nil { 149 req.Error = err 150 } 151 case arn.S3ObjectLambdaAccessPointARN: 152 err = updateRequestS3ObjectLambdaAccessPointEndpoint(req, tv) 153 if err != nil { 154 req.Error = err 155 } 156 case arn.OutpostAccessPointARN: 157 // outposts does not support FIPS regions 158 if resReq.UseFIPS() { 159 req.Error = s3shared.NewFIPSConfigurationError(resource, req.ClientInfo.PartitionID, 160 aws.StringValue(req.Config.Region), nil) 161 return 162 } 163 164 err = updateRequestOutpostAccessPointEndpoint(req, tv) 165 if err != nil { 166 req.Error = err 167 } 168 default: 169 req.Error = s3shared.NewInvalidARNError(resource, nil) 170 } 171 } 172 173 func updateBucketEndpointFromParams(r *request.Request) { 174 bucket, ok := bucketNameFromReqParams(r.Params) 175 if !ok { 176 // Ignore operation requests if the bucket name was not provided 177 // if this is an input validation error the validation handler 178 // will report it. 179 return 180 } 181 updateEndpointForS3Config(r, bucket) 182 } 183 184 func updateRequestAccessPointEndpoint(req *request.Request, accessPoint arn.AccessPointARN) error { 185 // Accelerate not supported 186 if aws.BoolValue(req.Config.S3UseAccelerate) { 187 return s3shared.NewClientConfiguredForAccelerateError(accessPoint, 188 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 189 } 190 191 // Ignore the disable host prefix for access points 192 req.Config.DisableEndpointHostPrefix = aws.Bool(false) 193 194 if err := accessPointEndpointBuilder(accessPoint).build(req); err != nil { 195 return err 196 } 197 198 removeBucketFromPath(req.HTTPRequest.URL) 199 200 return nil 201 } 202 203 func updateRequestS3ObjectLambdaAccessPointEndpoint(req *request.Request, accessPoint arn.S3ObjectLambdaAccessPointARN) error { 204 // DualStack not supported 205 if aws.BoolValue(req.Config.UseDualStack) { 206 return s3shared.NewClientConfiguredForDualStackError(accessPoint, 207 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 208 } 209 210 // Accelerate not supported 211 if aws.BoolValue(req.Config.S3UseAccelerate) { 212 return s3shared.NewClientConfiguredForAccelerateError(accessPoint, 213 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 214 } 215 216 // Ignore the disable host prefix for access points 217 req.Config.DisableEndpointHostPrefix = aws.Bool(false) 218 219 if err := s3ObjectLambdaAccessPointEndpointBuilder(accessPoint).build(req); err != nil { 220 return err 221 } 222 223 removeBucketFromPath(req.HTTPRequest.URL) 224 225 return nil 226 } 227 228 func updateRequestOutpostAccessPointEndpoint(req *request.Request, accessPoint arn.OutpostAccessPointARN) error { 229 // Accelerate not supported 230 if aws.BoolValue(req.Config.S3UseAccelerate) { 231 return s3shared.NewClientConfiguredForAccelerateError(accessPoint, 232 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 233 } 234 235 // Dualstack not supported 236 if aws.BoolValue(req.Config.UseDualStack) { 237 return s3shared.NewClientConfiguredForDualStackError(accessPoint, 238 req.ClientInfo.PartitionID, aws.StringValue(req.Config.Region), nil) 239 } 240 241 // Ignore the disable host prefix for access points 242 req.Config.DisableEndpointHostPrefix = aws.Bool(false) 243 244 if err := outpostAccessPointEndpointBuilder(accessPoint).build(req); err != nil { 245 return err 246 } 247 248 removeBucketFromPath(req.HTTPRequest.URL) 249 return nil 250 } 251 252 func removeBucketFromPath(u *url.URL) { 253 u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1) 254 if u.Path == "" { 255 u.Path = "/" 256 } 257 } 258 259 func buildWriteGetObjectResponseEndpoint(req *request.Request) { 260 // DualStack not supported 261 if aws.BoolValue(req.Config.UseDualStack) { 262 req.Error = awserr.New("ConfigurationError", "client configured for dualstack but not supported for operation", nil) 263 return 264 } 265 266 // Accelerate not supported 267 if aws.BoolValue(req.Config.S3UseAccelerate) { 268 req.Error = awserr.New("ConfigurationError", "client configured for accelerate but not supported for operation", nil) 269 return 270 } 271 272 signingName := s3ObjectsLambdaNamespace 273 signingRegion := req.ClientInfo.SigningRegion 274 275 if !hasCustomEndpoint(req) { 276 endpoint, err := resolveRegionalEndpoint(req, aws.StringValue(req.Config.Region), EndpointsID) 277 if err != nil { 278 req.Error = awserr.New(request.ErrCodeSerialization, "failed to resolve endpoint", err) 279 return 280 } 281 signingRegion = endpoint.SigningRegion 282 283 if err = updateRequestEndpoint(req, endpoint.URL); err != nil { 284 req.Error = err 285 return 286 } 287 updateS3HostPrefixForS3ObjectLambda(req) 288 } 289 290 redirectSigner(req, signingName, signingRegion) 291 }