123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- package minio
- import (
- "context"
- "net"
- "net/http"
- "net/url"
- "path"
- "sync"
- "github.com/minio/minio-go/v7/pkg/credentials"
- "github.com/minio/minio-go/v7/pkg/s3utils"
- "github.com/minio/minio-go/v7/pkg/signer"
- )
- type bucketLocationCache struct {
-
-
- sync.RWMutex
-
- items map[string]string
- }
- func newBucketLocationCache() *bucketLocationCache {
- return &bucketLocationCache{
- items: make(map[string]string),
- }
- }
- func (r *bucketLocationCache) Get(bucketName string) (location string, ok bool) {
- r.RLock()
- defer r.RUnlock()
- location, ok = r.items[bucketName]
- return
- }
- func (r *bucketLocationCache) Set(bucketName string, location string) {
- r.Lock()
- defer r.Unlock()
- r.items[bucketName] = location
- }
- func (r *bucketLocationCache) Delete(bucketName string) {
- r.Lock()
- defer r.Unlock()
- delete(r.items, bucketName)
- }
- func (c Client) GetBucketLocation(ctx context.Context, bucketName string) (string, error) {
- if err := s3utils.CheckValidBucketName(bucketName); err != nil {
- return "", err
- }
- return c.getBucketLocation(ctx, bucketName)
- }
- func (c Client) getBucketLocation(ctx context.Context, bucketName string) (string, error) {
- if err := s3utils.CheckValidBucketName(bucketName); err != nil {
- return "", err
- }
-
- if c.region != "" {
- return c.region, nil
- }
- if location, ok := c.bucketLocCache.Get(bucketName); ok {
- return location, nil
- }
-
- req, err := c.getBucketLocationRequest(ctx, bucketName)
- if err != nil {
- return "", err
- }
-
- resp, err := c.do(req)
- defer closeResponse(resp)
- if err != nil {
- return "", err
- }
- location, err := processBucketLocationResponse(resp, bucketName)
- if err != nil {
- return "", err
- }
- c.bucketLocCache.Set(bucketName, location)
- return location, nil
- }
- func processBucketLocationResponse(resp *http.Response, bucketName string) (bucketLocation string, err error) {
- if resp != nil {
- if resp.StatusCode != http.StatusOK {
- err = httpRespToErrorResponse(resp, bucketName, "")
- errResp := ToErrorResponse(err)
-
-
-
- switch errResp.Code {
- case "NotImplemented":
- if errResp.Server == "AmazonSnowball" {
- return "snowball", nil
- }
- case "AuthorizationHeaderMalformed":
- fallthrough
- case "InvalidRegion":
- fallthrough
- case "AccessDenied":
- if errResp.Region == "" {
- return "us-east-1", nil
- }
- return errResp.Region, nil
- }
- return "", err
- }
- }
-
- var locationConstraint string
- err = xmlDecoder(resp.Body, &locationConstraint)
- if err != nil {
- return "", err
- }
- location := locationConstraint
-
- if location == "" {
- location = "us-east-1"
- }
-
- if location == "EU" {
- location = "eu-west-1"
- }
-
-
- return location, nil
- }
- func (c Client) getBucketLocationRequest(ctx context.Context, bucketName string) (*http.Request, error) {
-
- urlValues := make(url.Values)
- urlValues.Set("location", "")
-
- targetURL := *c.endpointURL
-
- if h, p, err := net.SplitHostPort(targetURL.Host); err == nil {
- if targetURL.Scheme == "http" && p == "80" || targetURL.Scheme == "https" && p == "443" {
- targetURL.Host = h
- }
- }
- isVirtualHost := s3utils.IsVirtualHostSupported(targetURL, bucketName)
- var urlStr string
-
- if isVirtualHost && s3utils.IsAliyunOSSEndpoint(targetURL) {
- urlStr = c.endpointURL.Scheme + "://" + bucketName + "." + targetURL.Host + "/?location"
- } else {
- targetURL.Path = path.Join(bucketName, "") + "/"
- targetURL.RawQuery = urlValues.Encode()
- urlStr = targetURL.String()
- }
-
- req, err := http.NewRequestWithContext(ctx, http.MethodGet, urlStr, nil)
- if err != nil {
- return nil, err
- }
-
- c.setUserAgent(req)
-
- value, err := c.credsProvider.Get()
- if err != nil {
- return nil, err
- }
- var (
- signerType = value.SignerType
- accessKeyID = value.AccessKeyID
- secretAccessKey = value.SecretAccessKey
- sessionToken = value.SessionToken
- )
-
- if c.overrideSignerType != credentials.SignatureDefault {
- signerType = c.overrideSignerType
- }
-
-
- if value.SignerType == credentials.SignatureAnonymous {
- signerType = credentials.SignatureAnonymous
- }
- if signerType.IsAnonymous() {
- return req, nil
- }
- if signerType.IsV2() {
-
- isVirtualHost := false
- req = signer.SignV2(*req, accessKeyID, secretAccessKey, isVirtualHost)
- return req, nil
- }
-
- contentSha256 := emptySHA256Hex
- if c.secure {
- contentSha256 = unsignedPayload
- }
- req.Header.Set("X-Amz-Content-Sha256", contentSha256)
- req = signer.SignV4(*req, accessKeyID, secretAccessKey, sessionToken, "us-east-1")
- return req, nil
- }
|