github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/endpoint_builder.go (about) 1 package s3 2 3 import ( 4 "net/url" 5 "strings" 6 7 "github.com/aavshr/aws-sdk-go/aws" 8 "github.com/aavshr/aws-sdk-go/aws/awserr" 9 "github.com/aavshr/aws-sdk-go/aws/endpoints" 10 "github.com/aavshr/aws-sdk-go/aws/request" 11 "github.com/aavshr/aws-sdk-go/internal/s3shared" 12 "github.com/aavshr/aws-sdk-go/internal/s3shared/arn" 13 "github.com/aavshr/aws-sdk-go/private/protocol" 14 ) 15 16 const ( 17 accessPointPrefixLabel = "accesspoint" 18 accountIDPrefixLabel = "accountID" 19 accessPointPrefixTemplate = "{" + accessPointPrefixLabel + "}-{" + accountIDPrefixLabel + "}." 20 21 outpostPrefixLabel = "outpost" 22 outpostAccessPointPrefixTemplate = accessPointPrefixTemplate + "{" + outpostPrefixLabel + "}." 23 ) 24 25 // hasCustomEndpoint returns true if endpoint is a custom endpoint 26 func hasCustomEndpoint(r *request.Request) bool { 27 return len(aws.StringValue(r.Config.Endpoint)) > 0 28 } 29 30 // accessPointEndpointBuilder represents the endpoint builder for access point arn 31 type accessPointEndpointBuilder arn.AccessPointARN 32 33 // build builds the endpoint for corresponding access point arn 34 // 35 // For building an endpoint from access point arn, format used is: 36 // - Access point endpoint format : {accesspointName}-{accountId}.s3-accesspoint.{region}.{dnsSuffix} 37 // - example : myaccesspoint-012345678901.s3-accesspoint.us-west-2.amazonaws.com 38 // 39 // Access Point Endpoint requests are signed using "s3" as signing name. 40 // 41 func (a accessPointEndpointBuilder) build(req *request.Request) error { 42 resolveService := arn.AccessPointARN(a).Service 43 resolveRegion := arn.AccessPointARN(a).Region 44 cfgRegion := aws.StringValue(req.Config.Region) 45 46 if s3shared.IsFIPS(cfgRegion) { 47 if aws.BoolValue(req.Config.S3UseARNRegion) && s3shared.IsCrossRegion(req, resolveRegion) { 48 // FIPS with cross region is not supported, the SDK must fail 49 // because there is no well defined method for SDK to construct a 50 // correct FIPS endpoint. 51 return s3shared.NewClientConfiguredForCrossRegionFIPSError(arn.AccessPointARN(a), 52 req.ClientInfo.PartitionID, cfgRegion, nil) 53 } 54 resolveRegion = cfgRegion 55 } 56 57 endpoint, err := resolveRegionalEndpoint(req, resolveRegion, resolveService) 58 if err != nil { 59 return s3shared.NewFailedToResolveEndpointError(arn.AccessPointARN(a), 60 req.ClientInfo.PartitionID, cfgRegion, err) 61 } 62 63 endpoint.URL = endpoints.AddScheme(endpoint.URL, aws.BoolValue(req.Config.DisableSSL)) 64 65 if !hasCustomEndpoint(req) { 66 if err = updateRequestEndpoint(req, endpoint.URL); err != nil { 67 return err 68 } 69 70 // dual stack provided by endpoint resolver 71 updateS3HostForS3AccessPoint(req) 72 } 73 74 protocol.HostPrefixBuilder{ 75 Prefix: accessPointPrefixTemplate, 76 LabelsFn: a.hostPrefixLabelValues, 77 }.Build(req) 78 79 // signer redirection 80 redirectSigner(req, endpoint.SigningName, endpoint.SigningRegion) 81 82 err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host) 83 if err != nil { 84 return s3shared.NewInvalidARNError(arn.AccessPointARN(a), err) 85 } 86 87 return nil 88 } 89 90 func (a accessPointEndpointBuilder) hostPrefixLabelValues() map[string]string { 91 return map[string]string{ 92 accessPointPrefixLabel: arn.AccessPointARN(a).AccessPointName, 93 accountIDPrefixLabel: arn.AccessPointARN(a).AccountID, 94 } 95 } 96 97 // s3ObjectLambdaAccessPointEndpointBuilder represents the endpoint builder for an s3 object lambda access point arn 98 type s3ObjectLambdaAccessPointEndpointBuilder arn.S3ObjectLambdaAccessPointARN 99 100 // build builds the endpoint for corresponding access point arn 101 // 102 // For building an endpoint from access point arn, format used is: 103 // - Access point endpoint format : {accesspointName}-{accountId}.s3-object-lambda.{region}.{dnsSuffix} 104 // - example : myaccesspoint-012345678901.s3-object-lambda.us-west-2.amazonaws.com 105 // 106 // Access Point Endpoint requests are signed using "s3-object-lambda" as signing name. 107 // 108 func (a s3ObjectLambdaAccessPointEndpointBuilder) build(req *request.Request) error { 109 resolveRegion := arn.S3ObjectLambdaAccessPointARN(a).Region 110 cfgRegion := aws.StringValue(req.Config.Region) 111 112 if s3shared.IsFIPS(cfgRegion) { 113 if aws.BoolValue(req.Config.S3UseARNRegion) && s3shared.IsCrossRegion(req, resolveRegion) { 114 // FIPS with cross region is not supported, the SDK must fail 115 // because there is no well defined method for SDK to construct a 116 // correct FIPS endpoint. 117 return s3shared.NewClientConfiguredForCrossRegionFIPSError(arn.S3ObjectLambdaAccessPointARN(a), 118 req.ClientInfo.PartitionID, cfgRegion, nil) 119 } 120 resolveRegion = cfgRegion 121 } 122 123 endpoint, err := resolveRegionalEndpoint(req, resolveRegion, EndpointsID) 124 if err != nil { 125 return s3shared.NewFailedToResolveEndpointError(arn.S3ObjectLambdaAccessPointARN(a), 126 req.ClientInfo.PartitionID, cfgRegion, err) 127 } 128 129 endpoint.URL = endpoints.AddScheme(endpoint.URL, aws.BoolValue(req.Config.DisableSSL)) 130 131 endpoint.SigningName = s3ObjectsLambdaNamespace 132 133 if !hasCustomEndpoint(req) { 134 if err = updateRequestEndpoint(req, endpoint.URL); err != nil { 135 return err 136 } 137 138 updateS3HostPrefixForS3ObjectLambda(req) 139 } 140 141 protocol.HostPrefixBuilder{ 142 Prefix: accessPointPrefixTemplate, 143 LabelsFn: a.hostPrefixLabelValues, 144 }.Build(req) 145 146 // signer redirection 147 redirectSigner(req, endpoint.SigningName, endpoint.SigningRegion) 148 149 err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host) 150 if err != nil { 151 return s3shared.NewInvalidARNError(arn.S3ObjectLambdaAccessPointARN(a), err) 152 } 153 154 return nil 155 } 156 157 func (a s3ObjectLambdaAccessPointEndpointBuilder) hostPrefixLabelValues() map[string]string { 158 return map[string]string{ 159 accessPointPrefixLabel: arn.S3ObjectLambdaAccessPointARN(a).AccessPointName, 160 accountIDPrefixLabel: arn.S3ObjectLambdaAccessPointARN(a).AccountID, 161 } 162 } 163 164 // outpostAccessPointEndpointBuilder represents the Endpoint builder for outpost access point arn. 165 type outpostAccessPointEndpointBuilder arn.OutpostAccessPointARN 166 167 // build builds an endpoint corresponding to the outpost access point arn. 168 // 169 // For building an endpoint from outpost access point arn, format used is: 170 // - Outpost access point endpoint format : {accesspointName}-{accountId}.{outpostId}.s3-outposts.{region}.{dnsSuffix} 171 // - example : myaccesspoint-012345678901.op-01234567890123456.s3-outposts.us-west-2.amazonaws.com 172 // 173 // Outpost AccessPoint Endpoint request are signed using "s3-outposts" as signing name. 174 // 175 func (o outpostAccessPointEndpointBuilder) build(req *request.Request) error { 176 resolveRegion := o.Region 177 resolveService := o.Service 178 179 endpointsID := resolveService 180 if resolveService == s3OutpostsNamespace { 181 endpointsID = "s3" 182 } 183 184 endpoint, err := resolveRegionalEndpoint(req, resolveRegion, endpointsID) 185 if err != nil { 186 return s3shared.NewFailedToResolveEndpointError(o, 187 req.ClientInfo.PartitionID, resolveRegion, err) 188 } 189 190 endpoint.URL = endpoints.AddScheme(endpoint.URL, aws.BoolValue(req.Config.DisableSSL)) 191 192 if !hasCustomEndpoint(req) { 193 if err = updateRequestEndpoint(req, endpoint.URL); err != nil { 194 return err 195 } 196 updateHostPrefix(req, endpointsID, resolveService) 197 } 198 199 protocol.HostPrefixBuilder{ 200 Prefix: outpostAccessPointPrefixTemplate, 201 LabelsFn: o.hostPrefixLabelValues, 202 }.Build(req) 203 204 // set the signing region, name to resolved names from ARN 205 redirectSigner(req, resolveService, resolveRegion) 206 207 err = protocol.ValidateEndpointHost(req.Operation.Name, req.HTTPRequest.URL.Host) 208 if err != nil { 209 return s3shared.NewInvalidARNError(o, err) 210 } 211 212 return nil 213 } 214 215 func (o outpostAccessPointEndpointBuilder) hostPrefixLabelValues() map[string]string { 216 return map[string]string{ 217 accessPointPrefixLabel: o.AccessPointName, 218 accountIDPrefixLabel: o.AccountID, 219 outpostPrefixLabel: o.OutpostID, 220 } 221 } 222 223 func resolveRegionalEndpoint(r *request.Request, region string, endpointsID string) (endpoints.ResolvedEndpoint, error) { 224 return r.Config.EndpointResolver.EndpointFor(endpointsID, region, func(opts *endpoints.Options) { 225 opts.DisableSSL = aws.BoolValue(r.Config.DisableSSL) 226 opts.UseDualStack = aws.BoolValue(r.Config.UseDualStack) 227 opts.S3UsEast1RegionalEndpoint = endpoints.RegionalS3UsEast1Endpoint 228 }) 229 } 230 231 func updateRequestEndpoint(r *request.Request, endpoint string) (err error) { 232 r.HTTPRequest.URL, err = url.Parse(endpoint + r.Operation.HTTPPath) 233 if err != nil { 234 return awserr.New(request.ErrCodeSerialization, 235 "failed to parse endpoint URL", err) 236 } 237 238 return nil 239 } 240 241 // redirectSigner sets signing name, signing region for a request 242 func redirectSigner(req *request.Request, signingName string, signingRegion string) { 243 req.ClientInfo.SigningName = signingName 244 req.ClientInfo.SigningRegion = signingRegion 245 } 246 247 func updateS3HostForS3AccessPoint(req *request.Request) { 248 updateHostPrefix(req, "s3", s3AccessPointNamespace) 249 } 250 251 func updateS3HostPrefixForS3ObjectLambda(req *request.Request) { 252 updateHostPrefix(req, "s3", s3ObjectsLambdaNamespace) 253 } 254 255 func updateHostPrefix(req *request.Request, oldEndpointPrefix, newEndpointPrefix string) { 256 host := req.HTTPRequest.URL.Host 257 if strings.HasPrefix(host, oldEndpointPrefix) { 258 // replace service hostlabel oldEndpointPrefix to newEndpointPrefix 259 req.HTTPRequest.URL.Host = newEndpointPrefix + host[len(oldEndpointPrefix):] 260 } 261 }