aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/minio/minio-go/v7/bucket-cache.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/minio/minio-go/v7/bucket-cache.go')
-rw-r--r--vendor/github.com/minio/minio-go/v7/bucket-cache.go256
1 files changed, 256 insertions, 0 deletions
diff --git a/vendor/github.com/minio/minio-go/v7/bucket-cache.go b/vendor/github.com/minio/minio-go/v7/bucket-cache.go
new file mode 100644
index 0000000..b1d3b38
--- /dev/null
+++ b/vendor/github.com/minio/minio-go/v7/bucket-cache.go
@@ -0,0 +1,256 @@
1/*
2 * MinIO Go Library for Amazon S3 Compatible Cloud Storage
3 * Copyright 2015-2017 MinIO, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package minio
19
20import (
21 "context"
22 "net"
23 "net/http"
24 "net/url"
25 "path"
26 "sync"
27
28 "github.com/minio/minio-go/v7/pkg/credentials"
29 "github.com/minio/minio-go/v7/pkg/s3utils"
30 "github.com/minio/minio-go/v7/pkg/signer"
31)
32
33// bucketLocationCache - Provides simple mechanism to hold bucket
34// locations in memory.
35type bucketLocationCache struct {
36 // mutex is used for handling the concurrent
37 // read/write requests for cache.
38 sync.RWMutex
39
40 // items holds the cached bucket locations.
41 items map[string]string
42}
43
44// newBucketLocationCache - Provides a new bucket location cache to be
45// used internally with the client object.
46func newBucketLocationCache() *bucketLocationCache {
47 return &bucketLocationCache{
48 items: make(map[string]string),
49 }
50}
51
52// Get - Returns a value of a given key if it exists.
53func (r *bucketLocationCache) Get(bucketName string) (location string, ok bool) {
54 r.RLock()
55 defer r.RUnlock()
56 location, ok = r.items[bucketName]
57 return
58}
59
60// Set - Will persist a value into cache.
61func (r *bucketLocationCache) Set(bucketName, location string) {
62 r.Lock()
63 defer r.Unlock()
64 r.items[bucketName] = location
65}
66
67// Delete - Deletes a bucket name from cache.
68func (r *bucketLocationCache) Delete(bucketName string) {
69 r.Lock()
70 defer r.Unlock()
71 delete(r.items, bucketName)
72}
73
74// GetBucketLocation - get location for the bucket name from location cache, if not
75// fetch freshly by making a new request.
76func (c *Client) GetBucketLocation(ctx context.Context, bucketName string) (string, error) {
77 if err := s3utils.CheckValidBucketName(bucketName); err != nil {
78 return "", err
79 }
80 return c.getBucketLocation(ctx, bucketName)
81}
82
83// getBucketLocation - Get location for the bucketName from location map cache, if not
84// fetch freshly by making a new request.
85func (c *Client) getBucketLocation(ctx context.Context, bucketName string) (string, error) {
86 if err := s3utils.CheckValidBucketName(bucketName); err != nil {
87 return "", err
88 }
89
90 // Region set then no need to fetch bucket location.
91 if c.region != "" {
92 return c.region, nil
93 }
94
95 if location, ok := c.bucketLocCache.Get(bucketName); ok {
96 return location, nil
97 }
98
99 // Initialize a new request.
100 req, err := c.getBucketLocationRequest(ctx, bucketName)
101 if err != nil {
102 return "", err
103 }
104
105 // Initiate the request.
106 resp, err := c.do(req)
107 defer closeResponse(resp)
108 if err != nil {
109 return "", err
110 }
111 location, err := processBucketLocationResponse(resp, bucketName)
112 if err != nil {
113 return "", err
114 }
115 c.bucketLocCache.Set(bucketName, location)
116 return location, nil
117}
118
119// processes the getBucketLocation http response from the server.
120func processBucketLocationResponse(resp *http.Response, bucketName string) (bucketLocation string, err error) {
121 if resp != nil {
122 if resp.StatusCode != http.StatusOK {
123 err = httpRespToErrorResponse(resp, bucketName, "")
124 errResp := ToErrorResponse(err)
125 // For access denied error, it could be an anonymous
126 // request. Move forward and let the top level callers
127 // succeed if possible based on their policy.
128 switch errResp.Code {
129 case "NotImplemented":
130 switch errResp.Server {
131 case "AmazonSnowball":
132 return "snowball", nil
133 case "cloudflare":
134 return "us-east-1", nil
135 }
136 case "AuthorizationHeaderMalformed":
137 fallthrough
138 case "InvalidRegion":
139 fallthrough
140 case "AccessDenied":
141 if errResp.Region == "" {
142 return "us-east-1", nil
143 }
144 return errResp.Region, nil
145 }
146 return "", err
147 }
148 }
149
150 // Extract location.
151 var locationConstraint string
152 err = xmlDecoder(resp.Body, &locationConstraint)
153 if err != nil {
154 return "", err
155 }
156
157 location := locationConstraint
158 // Location is empty will be 'us-east-1'.
159 if location == "" {
160 location = "us-east-1"
161 }
162
163 // Location can be 'EU' convert it to meaningful 'eu-west-1'.
164 if location == "EU" {
165 location = "eu-west-1"
166 }
167
168 // Save the location into cache.
169
170 // Return.
171 return location, nil
172}
173
174// getBucketLocationRequest - Wrapper creates a new getBucketLocation request.
175func (c *Client) getBucketLocationRequest(ctx context.Context, bucketName string) (*http.Request, error) {
176 // Set location query.
177 urlValues := make(url.Values)
178 urlValues.Set("location", "")
179
180 // Set get bucket location always as path style.
181 targetURL := *c.endpointURL
182
183 // as it works in makeTargetURL method from api.go file
184 if h, p, err := net.SplitHostPort(targetURL.Host); err == nil {
185 if targetURL.Scheme == "http" && p == "80" || targetURL.Scheme == "https" && p == "443" {
186 targetURL.Host = h
187 if ip := net.ParseIP(h); ip != nil && ip.To16() != nil {
188 targetURL.Host = "[" + h + "]"
189 }
190 }
191 }
192
193 isVirtualStyle := c.isVirtualHostStyleRequest(targetURL, bucketName)
194
195 var urlStr string
196
197 if isVirtualStyle {
198 urlStr = c.endpointURL.Scheme + "://" + bucketName + "." + targetURL.Host + "/?location"
199 } else {
200 targetURL.Path = path.Join(bucketName, "") + "/"
201 targetURL.RawQuery = urlValues.Encode()
202 urlStr = targetURL.String()
203 }
204
205 // Get a new HTTP request for the method.
206 req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil)
207 if err != nil {
208 return nil, err
209 }
210
211 // Set UserAgent for the request.
212 c.setUserAgent(req)
213
214 // Get credentials from the configured credentials provider.
215 value, err := c.credsProvider.Get()
216 if err != nil {
217 return nil, err
218 }
219
220 var (
221 signerType = value.SignerType
222 accessKeyID = value.AccessKeyID
223 secretAccessKey = value.SecretAccessKey
224 sessionToken = value.SessionToken
225 )
226
227 // Custom signer set then override the behavior.
228 if c.overrideSignerType != credentials.SignatureDefault {
229 signerType = c.overrideSignerType
230 }
231
232 // If signerType returned by credentials helper is anonymous,
233 // then do not sign regardless of signerType override.
234 if value.SignerType == credentials.SignatureAnonymous {
235 signerType = credentials.SignatureAnonymous
236 }
237
238 if signerType.IsAnonymous() {
239 return req, nil
240 }
241
242 if signerType.IsV2() {
243 req = signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualStyle)
244 return req, nil
245 }
246
247 // Set sha256 sum for signature calculation only with signature version '4'.
248 contentSha256 := emptySHA256Hex
249 if c.secure {
250 contentSha256 = unsignedPayload
251 }
252
253 req.Header.Set("X-Amz-Content-Sha256", contentSha256)
254 req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
255 return req, nil
256}