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  }