9 "github.com/aws/aws-sdk-go/aws"
10 "github.com/aws/aws-sdk-go/aws/awserr"
11 "github.com/aws/aws-sdk-go/aws/request"
14 // an operationBlacklist is a list of operation names that should a
15 // request handler should not be executed with.
16 type operationBlacklist []string
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 {
29 var accelerateOpBlacklist = operationBlacklist{
30 opListBuckets, opCreateBucket, opDeleteBucket,
33 // Request handler to 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) {
37 forceHostStyle := aws.BoolValue(r.Config.S3ForcePathStyle)
38 accelerate := aws.BoolValue(r.Config.S3UseAccelerate)
40 if accelerate && accelerateOpBlacklist.Continue(r) {
42 if r.Config.Logger != nil {
43 r.Config.Logger.Log("ERROR: aws.Config.S3UseAccelerate is not compatible with aws.Config.S3ForcePathStyle, ignoring S3ForcePathStyle.")
46 updateEndpointForAccelerate(r)
47 } else if !forceHostStyle && r.Operation.Name != opGetBucketLocation {
48 updateEndpointForHostStyle(r)
52 func updateEndpointForHostStyle(r *request.Request) {
53 bucket, ok := bucketNameFromReqParams(r.Params)
55 // Ignore operation requests if the bucketname was not provided
56 // if this is an input validation error the validation handler
61 if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
62 // bucket name must be valid to put into the host
66 moveBucketToHost(r.HTTPRequest.URL, bucket)
70 accelElem = []byte("s3-accelerate.dualstack.")
73 func updateEndpointForAccelerate(r *request.Request) {
74 bucket, ok := bucketNameFromReqParams(r.Params)
76 // Ignore operation requests if the bucketname was not provided
77 // if this is an input validation error the validation handler
82 if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
83 r.Error = awserr.New("InvalidParameterException",
84 fmt.Sprintf("bucket name %s is not compatible with S3 Accelerate", bucket),
89 parts := strings.Split(r.HTTPRequest.URL.Host, ".")
91 r.Error = awserr.New("InvalidParameterExecption",
92 fmt.Sprintf("unable to update endpoint host for S3 accelerate, hostname invalid, %s",
93 r.HTTPRequest.URL.Host), nil)
97 if parts[0] == "s3" || strings.HasPrefix(parts[0], "s3-") {
98 parts[0] = "s3-accelerate"
100 for i := 1; i+1 < len(parts); i++ {
101 if parts[i] == aws.StringValue(r.Config.Region) {
102 parts = append(parts[:i], parts[i+1:]...)
107 r.HTTPRequest.URL.Host = strings.Join(parts, ".")
109 moveBucketToHost(r.HTTPRequest.URL, bucket)
112 // Attempts to retrieve the bucket name from the request input parameters.
113 // If no bucket is found, or the field is empty "", false will be returned.
114 func bucketNameFromReqParams(params interface{}) (string, bool) {
115 if iface, ok := params.(bucketGetter); ok {
116 b := iface.getBucket()
123 // hostCompatibleBucketName returns true if the request should
124 // put the bucket in the host. This is false if S3ForcePathStyle is
125 // explicitly set or if the bucket is not DNS compatible.
126 func hostCompatibleBucketName(u *url.URL, bucket string) bool {
127 // Bucket might be DNS compatible but dots in the hostname will fail
128 // certificate validation, so do not use host-style.
129 if u.Scheme == "https" && strings.Contains(bucket, ".") {
133 // if the bucket is DNS compatible
134 return dnsCompatibleBucketName(bucket)
137 var reDomain = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
138 var reIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`)
140 // dnsCompatibleBucketName returns true if the bucket name is DNS compatible.
141 // Buckets created outside of the classic region MUST be DNS compatible.
142 func dnsCompatibleBucketName(bucket string) bool {
143 return reDomain.MatchString(bucket) &&
144 !reIPAddress.MatchString(bucket) &&
145 !strings.Contains(bucket, "..")
148 // moveBucketToHost moves the bucket name from the URI path to URL host.
149 func moveBucketToHost(u *url.URL, bucket string) {
150 u.Host = bucket + "." + u.Host
151 u.Path = strings.Replace(u.Path, "/{Bucket}", "", -1)