github.com/minio/minio@v0.0.0-20240328213742-3f72439b8a27/cmd/post-policy-fan-out.go (about)

     1  // Copyright (c) 2015-2023 MinIO, Inc.
     2  //
     3  // This file is part of MinIO Object Storage stack
     4  //
     5  // This program is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Affero General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // This program is distributed in the hope that it will be useful
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU Affero General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Affero General Public License
    16  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17  
    18  package cmd
    19  
    20  import (
    21  	"bytes"
    22  	"context"
    23  	"sync"
    24  
    25  	"github.com/minio/minio-go/v7"
    26  	"github.com/minio/minio-go/v7/pkg/s3utils"
    27  	"github.com/minio/minio/internal/crypto"
    28  	"github.com/minio/minio/internal/hash"
    29  	xhttp "github.com/minio/minio/internal/http"
    30  	"github.com/minio/minio/internal/kms"
    31  )
    32  
    33  type fanOutOptions struct {
    34  	Kind     crypto.Type
    35  	KeyID    string
    36  	Key      []byte
    37  	KmsCtx   kms.Context
    38  	Checksum *hash.Checksum
    39  	MD5Hex   string
    40  }
    41  
    42  // fanOutPutObject takes an input source reader and fans out multiple PUT operations
    43  // based on the incoming fan-out request, a context cancellation by the caller
    44  // would ensure all fan-out operations are canceled.
    45  func fanOutPutObject(ctx context.Context, bucket string, objectAPI ObjectLayer, fanOutEntries []minio.PutObjectFanOutEntry, fanOutBuf []byte, opts fanOutOptions) ([]ObjectInfo, []error) {
    46  	errs := make([]error, len(fanOutEntries))
    47  	objInfos := make([]ObjectInfo, len(fanOutEntries))
    48  
    49  	var wg sync.WaitGroup
    50  	for i, req := range fanOutEntries {
    51  		wg.Add(1)
    52  		go func(idx int, req minio.PutObjectFanOutEntry) {
    53  			defer wg.Done()
    54  
    55  			objInfos[idx] = ObjectInfo{Name: req.Key}
    56  
    57  			hopts := hash.Options{
    58  				Size:       int64(len(fanOutBuf)),
    59  				MD5Hex:     opts.MD5Hex,
    60  				SHA256Hex:  "",
    61  				ActualSize: -1,
    62  				DisableMD5: true,
    63  			}
    64  			hr, err := hash.NewReaderWithOpts(ctx, bytes.NewReader(fanOutBuf), hopts)
    65  			if err != nil {
    66  				errs[idx] = err
    67  				return
    68  			}
    69  
    70  			reader := NewPutObjReader(hr)
    71  			defer func() {
    72  				if err := reader.Close(); err != nil {
    73  					errs[idx] = err
    74  				}
    75  				if err := hr.Close(); err != nil {
    76  					errs[idx] = err
    77  				}
    78  			}()
    79  
    80  			userDefined := make(map[string]string, len(req.UserMetadata))
    81  			for k, v := range req.UserMetadata {
    82  				userDefined[k] = v
    83  			}
    84  			userDefined[xhttp.AmzObjectTagging] = s3utils.TagEncode(req.UserTags)
    85  
    86  			if opts.Kind != nil {
    87  				encrd, objectEncryptionKey, err := newEncryptReader(ctx, hr, opts.Kind, opts.KeyID, opts.Key, bucket, req.Key, userDefined, opts.KmsCtx)
    88  				if err != nil {
    89  					errs[idx] = err
    90  					return
    91  				}
    92  
    93  				// do not try to verify encrypted content/
    94  				hr, err = hash.NewReader(ctx, encrd, -1, "", "", -1)
    95  				if err != nil {
    96  					errs[idx] = err
    97  					return
    98  				}
    99  
   100  				reader, err = reader.WithEncryption(hr, &objectEncryptionKey)
   101  				if err != nil {
   102  					errs[idx] = err
   103  					return
   104  				}
   105  			}
   106  
   107  			objInfo, err := objectAPI.PutObject(ctx, bucket, req.Key, reader, ObjectOptions{
   108  				Versioned:        globalBucketVersioningSys.PrefixEnabled(bucket, req.Key),
   109  				VersionSuspended: globalBucketVersioningSys.PrefixSuspended(bucket, req.Key),
   110  				UserDefined:      userDefined,
   111  			})
   112  			if err != nil {
   113  				errs[idx] = err
   114  				return
   115  			}
   116  			objInfos[idx] = objInfo
   117  		}(i, req)
   118  	}
   119  	wg.Wait()
   120  
   121  	return objInfos, errs
   122  }