]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/service/s3/host_style_bucket.go
a7fbc2de2f8013b8ad860c3c7cc9fae27f3ca7db
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / service / s3 / host_style_bucket.go
1 package s3
2
3 import (
4 "fmt"
5 "net/url"
6 "regexp"
7 "strings"
8
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"
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 // 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)
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)
47 } else if !forceHostStyle && r.Operation.Name != opGetBucketLocation {
48 updateEndpointForHostStyle(r)
49 }
50 }
51
52 func updateEndpointForHostStyle(r *request.Request) {
53 bucket, ok := bucketNameFromReqParams(r.Params)
54 if !ok {
55 // Ignore operation requests if the bucketname was not provided
56 // if this is an input validation error the validation handler
57 // will report it.
58 return
59 }
60
61 if !hostCompatibleBucketName(r.HTTPRequest.URL, bucket) {
62 // bucket name must be valid to put into the host
63 return
64 }
65
66 moveBucketToHost(r.HTTPRequest.URL, bucket)
67 }
68
69 var (
70 accelElem = []byte("s3-accelerate.dualstack.")
71 )
72
73 func updateEndpointForAccelerate(r *request.Request) {
74 bucket, ok := bucketNameFromReqParams(r.Params)
75 if !ok {
76 // Ignore operation requests if the bucketname was not provided
77 // if this is an input validation error the validation handler
78 // will report it.
79 return
80 }
81
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),
85 nil)
86 return
87 }
88
89 parts := strings.Split(r.HTTPRequest.URL.Host, ".")
90 if len(parts) < 3 {
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)
94 return
95 }
96
97 if parts[0] == "s3" || strings.HasPrefix(parts[0], "s3-") {
98 parts[0] = "s3-accelerate"
99 }
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:]...)
103 break
104 }
105 }
106
107 r.HTTPRequest.URL.Host = strings.Join(parts, ".")
108
109 moveBucketToHost(r.HTTPRequest.URL, bucket)
110 }
111
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()
117 return b, len(b) > 0
118 }
119
120 return "", false
121 }
122
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, ".") {
130 return false
131 }
132
133 // if the bucket is DNS compatible
134 return dnsCompatibleBucketName(bucket)
135 }
136
137 var reDomain = regexp.MustCompile(`^[a-z0-9][a-z0-9\.\-]{1,61}[a-z0-9]$`)
138 var reIPAddress = regexp.MustCompile(`^(\d+\.){3}\d+$`)
139
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, "..")
146 }
147
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)
152 if u.Path == "" {
153 u.Path = "/"
154 }
155 }