]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/endpoints/v3model.go
Initial transfer of provider code
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / endpoints / v3model.go
1 package endpoints
2
3 import (
4 "fmt"
5 "regexp"
6 "strconv"
7 "strings"
8 )
9
10 type partitions []partition
11
12 func (ps partitions) EndpointFor(service, region string, opts ...func(*Options)) (ResolvedEndpoint, error) {
13 var opt Options
14 opt.Set(opts...)
15
16 for i := 0; i < len(ps); i++ {
17 if !ps[i].canResolveEndpoint(service, region, opt.StrictMatching) {
18 continue
19 }
20
21 return ps[i].EndpointFor(service, region, opts...)
22 }
23
24 // If loose matching fallback to first partition format to use
25 // when resolving the endpoint.
26 if !opt.StrictMatching && len(ps) > 0 {
27 return ps[0].EndpointFor(service, region, opts...)
28 }
29
30 return ResolvedEndpoint{}, NewUnknownEndpointError("all partitions", service, region, []string{})
31 }
32
33 // Partitions satisfies the EnumPartitions interface and returns a list
34 // of Partitions representing each partition represented in the SDK's
35 // endpoints model.
36 func (ps partitions) Partitions() []Partition {
37 parts := make([]Partition, 0, len(ps))
38 for i := 0; i < len(ps); i++ {
39 parts = append(parts, ps[i].Partition())
40 }
41
42 return parts
43 }
44
45 type partition struct {
46 ID string `json:"partition"`
47 Name string `json:"partitionName"`
48 DNSSuffix string `json:"dnsSuffix"`
49 RegionRegex regionRegex `json:"regionRegex"`
50 Defaults endpoint `json:"defaults"`
51 Regions regions `json:"regions"`
52 Services services `json:"services"`
53 }
54
55 func (p partition) Partition() Partition {
56 return Partition{
57 id: p.ID,
58 p: &p,
59 }
60 }
61
62 func (p partition) canResolveEndpoint(service, region string, strictMatch bool) bool {
63 s, hasService := p.Services[service]
64 _, hasEndpoint := s.Endpoints[region]
65
66 if hasEndpoint && hasService {
67 return true
68 }
69
70 if strictMatch {
71 return false
72 }
73
74 return p.RegionRegex.MatchString(region)
75 }
76
77 func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (resolved ResolvedEndpoint, err error) {
78 var opt Options
79 opt.Set(opts...)
80
81 s, hasService := p.Services[service]
82 if !(hasService || opt.ResolveUnknownService) {
83 // Only return error if the resolver will not fallback to creating
84 // endpoint based on service endpoint ID passed in.
85 return resolved, NewUnknownServiceError(p.ID, service, serviceList(p.Services))
86 }
87
88 e, hasEndpoint := s.endpointForRegion(region)
89 if !hasEndpoint && opt.StrictMatching {
90 return resolved, NewUnknownEndpointError(p.ID, service, region, endpointList(s.Endpoints))
91 }
92
93 defs := []endpoint{p.Defaults, s.Defaults}
94 return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
95 }
96
97 func serviceList(ss services) []string {
98 list := make([]string, 0, len(ss))
99 for k := range ss {
100 list = append(list, k)
101 }
102 return list
103 }
104 func endpointList(es endpoints) []string {
105 list := make([]string, 0, len(es))
106 for k := range es {
107 list = append(list, k)
108 }
109 return list
110 }
111
112 type regionRegex struct {
113 *regexp.Regexp
114 }
115
116 func (rr *regionRegex) UnmarshalJSON(b []byte) (err error) {
117 // Strip leading and trailing quotes
118 regex, err := strconv.Unquote(string(b))
119 if err != nil {
120 return fmt.Errorf("unable to strip quotes from regex, %v", err)
121 }
122
123 rr.Regexp, err = regexp.Compile(regex)
124 if err != nil {
125 return fmt.Errorf("unable to unmarshal region regex, %v", err)
126 }
127 return nil
128 }
129
130 type regions map[string]region
131
132 type region struct {
133 Description string `json:"description"`
134 }
135
136 type services map[string]service
137
138 type service struct {
139 PartitionEndpoint string `json:"partitionEndpoint"`
140 IsRegionalized boxedBool `json:"isRegionalized,omitempty"`
141 Defaults endpoint `json:"defaults"`
142 Endpoints endpoints `json:"endpoints"`
143 }
144
145 func (s *service) endpointForRegion(region string) (endpoint, bool) {
146 if s.IsRegionalized == boxedFalse {
147 return s.Endpoints[s.PartitionEndpoint], region == s.PartitionEndpoint
148 }
149
150 if e, ok := s.Endpoints[region]; ok {
151 return e, true
152 }
153
154 // Unable to find any matching endpoint, return
155 // blank that will be used for generic endpoint creation.
156 return endpoint{}, false
157 }
158
159 type endpoints map[string]endpoint
160
161 type endpoint struct {
162 Hostname string `json:"hostname"`
163 Protocols []string `json:"protocols"`
164 CredentialScope credentialScope `json:"credentialScope"`
165
166 // Custom fields not modeled
167 HasDualStack boxedBool `json:"-"`
168 DualStackHostname string `json:"-"`
169
170 // Signature Version not used
171 SignatureVersions []string `json:"signatureVersions"`
172
173 // SSLCommonName not used.
174 SSLCommonName string `json:"sslCommonName"`
175 }
176
177 const (
178 defaultProtocol = "https"
179 defaultSigner = "v4"
180 )
181
182 var (
183 protocolPriority = []string{"https", "http"}
184 signerPriority = []string{"v4", "v2"}
185 )
186
187 func getByPriority(s []string, p []string, def string) string {
188 if len(s) == 0 {
189 return def
190 }
191
192 for i := 0; i < len(p); i++ {
193 for j := 0; j < len(s); j++ {
194 if s[j] == p[i] {
195 return s[j]
196 }
197 }
198 }
199
200 return s[0]
201 }
202
203 func (e endpoint) resolve(service, region, dnsSuffix string, defs []endpoint, opts Options) ResolvedEndpoint {
204 var merged endpoint
205 for _, def := range defs {
206 merged.mergeIn(def)
207 }
208 merged.mergeIn(e)
209 e = merged
210
211 hostname := e.Hostname
212
213 // Offset the hostname for dualstack if enabled
214 if opts.UseDualStack && e.HasDualStack == boxedTrue {
215 hostname = e.DualStackHostname
216 }
217
218 u := strings.Replace(hostname, "{service}", service, 1)
219 u = strings.Replace(u, "{region}", region, 1)
220 u = strings.Replace(u, "{dnsSuffix}", dnsSuffix, 1)
221
222 scheme := getEndpointScheme(e.Protocols, opts.DisableSSL)
223 u = fmt.Sprintf("%s://%s", scheme, u)
224
225 signingRegion := e.CredentialScope.Region
226 if len(signingRegion) == 0 {
227 signingRegion = region
228 }
229 signingName := e.CredentialScope.Service
230 if len(signingName) == 0 {
231 signingName = service
232 }
233
234 return ResolvedEndpoint{
235 URL: u,
236 SigningRegion: signingRegion,
237 SigningName: signingName,
238 SigningMethod: getByPriority(e.SignatureVersions, signerPriority, defaultSigner),
239 }
240 }
241
242 func getEndpointScheme(protocols []string, disableSSL bool) string {
243 if disableSSL {
244 return "http"
245 }
246
247 return getByPriority(protocols, protocolPriority, defaultProtocol)
248 }
249
250 func (e *endpoint) mergeIn(other endpoint) {
251 if len(other.Hostname) > 0 {
252 e.Hostname = other.Hostname
253 }
254 if len(other.Protocols) > 0 {
255 e.Protocols = other.Protocols
256 }
257 if len(other.SignatureVersions) > 0 {
258 e.SignatureVersions = other.SignatureVersions
259 }
260 if len(other.CredentialScope.Region) > 0 {
261 e.CredentialScope.Region = other.CredentialScope.Region
262 }
263 if len(other.CredentialScope.Service) > 0 {
264 e.CredentialScope.Service = other.CredentialScope.Service
265 }
266 if len(other.SSLCommonName) > 0 {
267 e.SSLCommonName = other.SSLCommonName
268 }
269 if other.HasDualStack != boxedBoolUnset {
270 e.HasDualStack = other.HasDualStack
271 }
272 if len(other.DualStackHostname) > 0 {
273 e.DualStackHostname = other.DualStackHostname
274 }
275 }
276
277 type credentialScope struct {
278 Region string `json:"region"`
279 Service string `json:"service"`
280 }
281
282 type boxedBool int
283
284 func (b *boxedBool) UnmarshalJSON(buf []byte) error {
285 v, err := strconv.ParseBool(string(buf))
286 if err != nil {
287 return err
288 }
289
290 if v {
291 *b = boxedTrue
292 } else {
293 *b = boxedFalse
294 }
295
296 return nil
297 }
298
299 const (
300 boxedBoolUnset boxedBool = iota
301 boxedFalse
302 boxedTrue
303 )