github.com/aavshr/aws-sdk-go@v1.41.3/service/s3/host_style_bucket.go (about) 1 package s3 2 3 import ( 4 "fmt" 5 "net/url" 6 "regexp" 7 "strings" 8 9 "github.com/aavshr/aws-sdk-go/aws" 10 "github.com/aavshr/aws-sdk-go/aws/awserr" 11 "github.com/aavshr/aws-sdk-go/aws/request" 12 ) 13 14 // an operationBlacklist is a list of operation names that should a 15 // request handler should not be executed with. 16 type operationBlacklist []string 17 18 // Continue will return true of the Request's operation name is not 19 // in the blacklist. False otherwise. 20 func (b operationBlacklist) Continue(r *request.Request) bool { 21 for i := 0; i < len(b); i++ { 22 if b[i] == r.Operation.Name { 23 return false 24 } 25 } 26 return true 27 } 28 29 var accelerateOpBlacklist = operationBlacklist{ 30 opListBuckets, opCreateBucket, opDeleteBucket, 31 } 32 33 // Automatically add the bucket name to the endpoint domain 34 // if possible. This style of bucket is valid for all bucket names which are 35 // DNS compatible and do not contain "." 36 func updateEndpointForS3Config(r *request.Request, bucketName string) { 37 forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle) 38 accelerate := aws.BoolValue(r.Config.S3UseAccelerate) 39 40 if accelerate && accelerateOpBlacklist.Continue(r) { 41 if forceHostStyle { 42 if r.Config.Logger != nil { 43 r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.") 44 } 45 } 46 updateEndpointForAccelerate(r, bucketName) 47 } else if !forceHostStyle && r.Operation.Name != opGetBucketLocation { 48 updateEndpointForHostStyle(r, bucketName) 49 } 50 } 51 52 func updateEndpointForHostStyle(r *request.Request, bucketName string) { 53 if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) { 54 // bucket name must be valid to put into the host 55 return 56 } 57 58 moveBucketToHost(r.HTTPRequest.URL, bucketName) 59 } 60 61 var ( 62 accelElem = []byte("s3-accelerate.dualstack.") 63 ) 64 65 func updateEndpointForAccelerate(r *request.Request, bucketName string) { 66 if !hostCompatibleBucketName(r.HTTPRequest.URL, bucketName) { 67 r.Error = awserr.New("InvalidParameterException", 68 fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucketName), 69 nil) 70 return 71 } 72 73 parts := strings.Split(r.HTTPRequest.URL.Host, ".") 74 if len(parts) < 3 { 75 r.Error = awserr.New("InvalidParameterExecption", 76 fmt.Sprintf("unable to update endpoint host for S3 accelerate, hostname invalid, %s", 77 r.HTTPRequest.URL.Host), nil) 78 return 79 } 80 81 if parts[0] == "s3" || strings.HasPrefix(parts[0], "s3-") { 82 parts[0] = "s3-accelerate" 83 } 84 for i := 1; i+1 < len(parts); i++ { 85 if parts[i] == aws.StringValue(r.Config.Region) { 86 parts = append(parts[:i], parts[i+1:]...) 87 break 88 } 89 } 90 91 r.HTTPRequest.URL.Host = strings.Join(parts, ".") 92 93 moveBucketToHost(r.HTTPRequest.URL, bucketName) 94 } 95 96 // Attempts to retrieve the bucket name from the request input parameters. 97 // If no bucket is found, or the field is empty "", false will be returned. 98 func bucketNameFromReqParams(params interface{}) (string, bool) { 99 if iface, ok := params.(bucketGetter); ok { 100 b := iface.getBucket() 101 return b, len(b) > 0 102 } 103 104 return "", false 105 } 106 107 // hostCompatibleBucketName returns true if the request should 108 // put the bucket in the host. This is false if S3ForcePathStyle is 109 // explicitly set or if the bucket is not DNS compatible. 110 func hostCompatibleBucketName(u *url.URL, bucket string) bool { 111 // Bucket might be DNS compatible but dots in the hostname will fail 112 // certificate validation, so do not use host-style. 113 if u.Scheme == "https" && strings.Contains(bucket, ".") { 114 return false 115 } 116 117 // if the bucket is DNS compatible 118 return dnsCompatibleBucketName(bucket) 119 } 120 121 var reDomain = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`) 122 var reIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`) 123 124 // dnsCompatibleBucketName returns true if the bucket name is DNS compatible. 125 // Buckets created outside of the classic region MUST be DNS compatible. 126 func dnsCompatibleBucketName(bucket string) bool { 127 return reDomain.MatchString(bucket) && 128 !reIPAddress.MatchString(bucket) && 129 !strings.Contains(bucket, "..") 130 } 131 132 // moveBucketToHost moves the bucket name from the URI path to URL host. 133 func moveBucketToHost(u *url.URL, bucket string) { 134 u.Host = bucket + "." + u.Host 135 removeBucketFromPath(u) 136 }