diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index cc43ef582..e4249851f 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -309,7 +309,7 @@ func (atb *adminXLTestBed) GenerateHealTestData(t *testing.T) { objectName := fmt.Sprintf("%s-%d", objName, i) _, err = atb.objLayer.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("hello")), - int64(len("hello")), "", ""), nil, ObjectOptions{}) + int64(len("hello")), "", ""), ObjectOptions{}) if err != nil { t.Fatalf("Failed to create %s - %v", objectName, err) @@ -321,7 +321,7 @@ func (atb *adminXLTestBed) GenerateHealTestData(t *testing.T) { { objName := "mpObject" uploadID, err := atb.objLayer.NewMultipartUpload(context.Background(), bucketName, - objName, nil, ObjectOptions{}) + objName, ObjectOptions{}) if err != nil { t.Fatalf("mp new error: %v", err) } diff --git a/cmd/benchmark-utils_test.go b/cmd/benchmark-utils_test.go index e18aafc38..95c78b636 100644 --- a/cmd/benchmark-utils_test.go +++ b/cmd/benchmark-utils_test.go @@ -49,7 +49,6 @@ func runPutObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) { textData := generateBytesData(objSize) // generate md5sum for the generated data. // md5sum of the data to written is required as input for PutObject. - metadata := make(map[string]string) md5hex := getMD5Hash(textData) sha256hex := "" @@ -61,7 +60,7 @@ func runPutObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) { for i := 0; i < b.N; i++ { // insert the object. objInfo, err := obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), - mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), metadata, ObjectOptions{}) + mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) if err != nil { b.Fatal(err) } @@ -96,9 +95,7 @@ func runPutObjectPartBenchmark(b *testing.B, obj ObjectLayer, partSize int) { textData := generateBytesData(objSize) // generate md5sum for the generated data. // md5sum of the data to written is required as input for NewMultipartUpload. - metadata := make(map[string]string) - opts := ObjectOptions{} - uploadID, err = obj.NewMultipartUpload(context.Background(), bucket, object, metadata, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucket, object, ObjectOptions{}) if err != nil { b.Fatal(err) } @@ -123,7 +120,7 @@ func runPutObjectPartBenchmark(b *testing.B, obj ObjectLayer, partSize int) { md5hex = getMD5Hash([]byte(textPartData)) var partInfo PartInfo partInfo, err = obj.PutObjectPart(context.Background(), bucket, object, uploadID, j, - mustGetPutObjReader(b, bytes.NewBuffer(textPartData), int64(len(textPartData)), md5hex, sha256hex), opts) + mustGetPutObjReader(b, bytes.NewBuffer(textPartData), int64(len(textPartData)), md5hex, sha256hex), ObjectOptions{}) if err != nil { b.Fatal(err) } @@ -194,7 +191,6 @@ func runGetObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) { // generate etag for the generated data. // etag of the data to written is required as input for PutObject. // PutObject is the functions which writes the data onto the FS/XL backend. - metadata := make(map[string]string) // get text data generated for number of bytes equal to object size. md5hex := getMD5Hash(textData) @@ -204,7 +200,7 @@ func runGetObjectBenchmark(b *testing.B, obj ObjectLayer, objSize int) { // insert the object. var objInfo ObjectInfo objInfo, err = obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), - mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), metadata, ObjectOptions{}) + mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) if err != nil { b.Fatal(err) } @@ -289,7 +285,6 @@ func runPutObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) { textData := generateBytesData(objSize) // generate md5sum for the generated data. // md5sum of the data to written is required as input for PutObject. - metadata := make(map[string]string) md5hex := getMD5Hash([]byte(textData)) sha256hex := "" @@ -304,7 +299,7 @@ func runPutObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) { for pb.Next() { // insert the object. objInfo, err := obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), - mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), metadata, ObjectOptions{}) + mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) if err != nil { b.Fatal(err) } @@ -335,7 +330,6 @@ func runGetObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) { // generate md5sum for the generated data. // md5sum of the data to written is required as input for PutObject. // PutObject is the functions which writes the data onto the FS/XL backend. - metadata := make(map[string]string) md5hex := getMD5Hash([]byte(textData)) sha256hex := "" @@ -344,7 +338,7 @@ func runGetObjectBenchmarkParallel(b *testing.B, obj ObjectLayer, objSize int) { // insert the object. var objInfo ObjectInfo objInfo, err = obj.PutObject(context.Background(), bucket, "object"+strconv.Itoa(i), - mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), metadata, ObjectOptions{}) + mustGetPutObjReader(b, bytes.NewBuffer(textData), int64(len(textData)), md5hex, sha256hex), ObjectOptions{}) if err != nil { b.Fatal(err) } diff --git a/cmd/bucket-handlers.go b/cmd/bucket-handlers.go index 04985b541..6f97cfa2c 100644 --- a/cmd/bucket-handlers.go +++ b/cmd/bucket-handlers.go @@ -633,7 +633,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h } // get gateway encryption options var opts ObjectOptions - opts, err = putEncryptionOpts(ctx, r, bucket, object, nil) + opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -664,7 +664,7 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h } } - objInfo, err := objectAPI.PutObject(ctx, bucket, object, pReader, metadata, opts) + objInfo, err := objectAPI.PutObject(ctx, bucket, object, pReader, opts) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return diff --git a/cmd/bucket-handlers_test.go b/cmd/bucket-handlers_test.go index 23fe53b53..0beedf856 100644 --- a/cmd/bucket-handlers_test.go +++ b/cmd/bucket-handlers_test.go @@ -625,7 +625,7 @@ func testAPIDeleteMultipleObjectsHandler(obj ObjectLayer, instanceType, bucketNa for i := 0; i < 10; i++ { objectName := "test-object-" + strconv.Itoa(i) // uploading the object. - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewBuffer(contentBytes), int64(len(contentBytes)), "", sha256sum), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewBuffer(contentBytes), int64(len(contentBytes)), "", sha256sum), ObjectOptions{}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object %d: Error uploading object: %v", i, err) diff --git a/cmd/config-common.go b/cmd/config-common.go index cf597cd3d..27e722beb 100644 --- a/cmd/config-common.go +++ b/cmd/config-common.go @@ -78,7 +78,7 @@ func saveConfig(ctx context.Context, objAPI ObjectLayer, configFile string, data return err } - _, err = objAPI.PutObject(ctx, minioMetaBucket, configFile, NewPutObjReader(hashReader, nil, nil), nil, ObjectOptions{}) + _, err = objAPI.PutObject(ctx, minioMetaBucket, configFile, NewPutObjReader(hashReader, nil, nil), ObjectOptions{}) return err } diff --git a/cmd/disk-cache-fs.go b/cmd/disk-cache-fs.go index e3de91fc8..aea1bc12d 100644 --- a/cmd/disk-cache-fs.go +++ b/cmd/disk-cache-fs.go @@ -257,7 +257,7 @@ func (cfs *cacheFSObjects) IsOnline() bool { } // Caches the object to disk -func (cfs *cacheFSObjects) Put(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) error { +func (cfs *cacheFSObjects) Put(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) error { if cfs.diskUsageHigh() { select { case cfs.purgeChan <- struct{}{}: @@ -274,7 +274,7 @@ func (cfs *cacheFSObjects) Put(ctx context.Context, bucket, object string, data return pErr } } - _, err := cfs.PutObject(ctx, bucket, object, data, metadata, opts) + _, err := cfs.PutObject(ctx, bucket, object, data, opts) // if err is due to disk being offline , mark cache drive as offline if IsErr(err, baseErrs...) { cfs.setOnline(false) @@ -300,7 +300,7 @@ func (cfs *cacheFSObjects) Exists(ctx context.Context, bucket, object string) bo // Identical to fs PutObject operation except that it uses ETag in metadata // headers. -func (cfs *cacheFSObjects) PutObject(ctx context.Context, bucket string, object string, r *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { +func (cfs *cacheFSObjects) PutObject(ctx context.Context, bucket string, object string, r *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { data := r.Reader fs := cfs.FSObjects // Lock the object. @@ -312,7 +312,7 @@ func (cfs *cacheFSObjects) PutObject(ctx context.Context, bucket string, object // No metadata is set, allocate a new one. meta := make(map[string]string) - for k, v := range metadata { + for k, v := range opts.UserDefined { meta[k] = v } @@ -438,7 +438,7 @@ func (cfs *cacheFSObjects) PutObject(ctx context.Context, bucket string, object // Implements S3 compatible initiate multipart API. Operation here is identical // to fs backend implementation - with the exception that cache FS uses the uploadID // generated on the backend -func (cfs *cacheFSObjects) NewMultipartUpload(ctx context.Context, bucket, object string, meta map[string]string, uploadID string, opts ObjectOptions) (string, error) { +func (cfs *cacheFSObjects) NewMultipartUpload(ctx context.Context, bucket, object string, uploadID string, opts ObjectOptions) (string, error) { if cfs.diskUsageHigh() { select { case cfs.purgeChan <- struct{}{}: @@ -472,7 +472,7 @@ func (cfs *cacheFSObjects) NewMultipartUpload(ctx context.Context, bucket, objec // Initialize fs.json values. fsMeta := newFSMetaV1() - fsMeta.Meta = meta + fsMeta.Meta = opts.UserDefined fsMetaBytes, err := json.Marshal(fsMeta) if err != nil { diff --git a/cmd/disk-cache.go b/cmd/disk-cache.go index a27f240f2..936582732 100644 --- a/cmd/disk-cache.go +++ b/cmd/disk-cache.go @@ -60,13 +60,13 @@ type cacheObjects struct { GetObjectNInfoFn func(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (gr *GetObjectReader, err error) GetObjectFn func(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) (err error) GetObjectInfoFn func(ctx context.Context, bucket, object string, opts ObjectOptions) (objInfo ObjectInfo, err error) - PutObjectFn func(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) + PutObjectFn func(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) DeleteObjectFn func(ctx context.Context, bucket, object string) error ListObjectsFn func(ctx context.Context, bucket, prefix, marker, delimiter string, maxKeys int) (result ListObjectsInfo, err error) ListObjectsV2Fn func(ctx context.Context, bucket, prefix, continuationToken, delimiter string, maxKeys int, fetchOwner bool, startAfter string) (result ListObjectsV2Info, err error) ListBucketsFn func(ctx context.Context) (buckets []BucketInfo, err error) GetBucketInfoFn func(ctx context.Context, bucket string) (bucketInfo BucketInfo, err error) - NewMultipartUploadFn func(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) + NewMultipartUploadFn func(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) PutObjectPartFn func(ctx context.Context, bucket, object, uploadID string, partID int, data *PutObjReader, opts ObjectOptions) (info PartInfo, err error) AbortMultipartUploadFn func(ctx context.Context, bucket, object, uploadID string) error CompleteMultipartUploadFn func(ctx context.Context, bucket, object, uploadID string, uploadedParts []CompletePart, opts ObjectOptions) (objInfo ObjectInfo, err error) @@ -92,11 +92,11 @@ type CacheObjectLayer interface { GetObjectNInfo(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (gr *GetObjectReader, err error) GetObject(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) (err error) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (objInfo ObjectInfo, err error) - PutObject(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) + PutObject(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) DeleteObject(ctx context.Context, bucket, object string) error // Multipart operations. - NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) + NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) PutObjectPart(ctx context.Context, bucket, object, uploadID string, partID int, data *PutObjReader, opts ObjectOptions) (info PartInfo, err error) AbortMultipartUpload(ctx context.Context, bucket, object, uploadID string) error CompleteMultipartUpload(ctx context.Context, bucket, object, uploadID string, uploadedParts []CompletePart, opts ObjectOptions) (objInfo ObjectInfo, err error) @@ -246,8 +246,7 @@ func (c cacheObjects) GetObjectNInfo(ctx context.Context, bucket, object string, } go func() { - opts := ObjectOptions{} - putErr := dcache.Put(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), c.getMetadata(bkReader.ObjInfo), opts) + putErr := dcache.Put(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), ObjectOptions{UserDefined: c.getMetadata(bkReader.ObjInfo)}) // close the write end of the pipe, so the error gets // propagated to getObjReader pipeWriter.CloseWithError(putErr) @@ -320,7 +319,9 @@ func (c cacheObjects) GetObject(ctx context.Context, bucket, object string, star gerr := GetObjectFn(ctx, bucket, object, 0, objInfo.Size, io.MultiWriter(writer, pipeWriter), etag, opts) pipeWriter.CloseWithError(gerr) // Close writer explicitly signaling we wrote all data. }() - err = dcache.Put(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), c.getMetadata(objInfo), opts) + + opts.UserDefined = c.getMetadata(objInfo) + err = dcache.Put(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), opts) if err != nil { return err } @@ -644,25 +645,25 @@ func (c cacheObjects) isCacheExclude(bucket, object string) bool { } // PutObject - caches the uploaded object for single Put operations -func (c cacheObjects) PutObject(ctx context.Context, bucket, object string, r *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { +func (c cacheObjects) PutObject(ctx context.Context, bucket, object string, r *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { putObjectFn := c.PutObjectFn data := r.Reader dcache, err := c.cache.getCacheFS(ctx, bucket, object) if err != nil { // disk cache could not be located,execute backend call. - return putObjectFn(ctx, bucket, object, r, metadata, opts) + return putObjectFn(ctx, bucket, object, r, opts) } size := r.Size() // fetch from backend if there is no space on cache drive if !dcache.diskAvailable(size) { - return putObjectFn(ctx, bucket, object, r, metadata, opts) + return putObjectFn(ctx, bucket, object, r, opts) } // fetch from backend if cache exclude pattern or cache-control // directive set to exclude - if c.isCacheExclude(bucket, object) || filterFromCache(metadata) { + if c.isCacheExclude(bucket, object) || filterFromCache(opts.UserDefined) { dcache.Delete(ctx, bucket, object) - return putObjectFn(ctx, bucket, object, r, metadata, opts) + return putObjectFn(ctx, bucket, object, r, opts) } objInfo = ObjectInfo{} // Initialize pipe to stream data to backend @@ -680,7 +681,7 @@ func (c cacheObjects) PutObject(ctx context.Context, bucket, object string, r *P oinfoCh := make(chan ObjectInfo) errCh := make(chan error) go func() { - oinfo, perr := putObjectFn(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), metadata, opts) + oinfo, perr := putObjectFn(ctx, bucket, object, NewPutObjReader(hashReader, nil, nil), opts) if perr != nil { pipeWriter.CloseWithError(perr) wPipe.CloseWithError(perr) @@ -693,7 +694,7 @@ func (c cacheObjects) PutObject(ctx context.Context, bucket, object string, r *P }() go func() { - if err = dcache.Put(ctx, bucket, object, NewPutObjReader(cHashReader, nil, nil), metadata, opts); err != nil { + if err = dcache.Put(ctx, bucket, object, NewPutObjReader(cHashReader, nil, nil), opts); err != nil { wPipe.CloseWithError(err) return } @@ -712,25 +713,25 @@ func (c cacheObjects) PutObject(ctx context.Context, bucket, object string, r *P } // NewMultipartUpload - Starts a new multipart upload operation to backend and cache. -func (c cacheObjects) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) { +func (c cacheObjects) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) { newMultipartUploadFn := c.NewMultipartUploadFn - if c.isCacheExclude(bucket, object) || filterFromCache(metadata) { - return newMultipartUploadFn(ctx, bucket, object, metadata, opts) + if c.isCacheExclude(bucket, object) || filterFromCache(opts.UserDefined) { + return newMultipartUploadFn(ctx, bucket, object, opts) } dcache, err := c.cache.getCacheFS(ctx, bucket, object) if err != nil { // disk cache could not be located,execute backend call. - return newMultipartUploadFn(ctx, bucket, object, metadata, opts) + return newMultipartUploadFn(ctx, bucket, object, opts) } - uploadID, err = newMultipartUploadFn(ctx, bucket, object, metadata, opts) + uploadID, err = newMultipartUploadFn(ctx, bucket, object, opts) if err != nil { return } // create new multipart upload in cache with same uploadID - dcache.NewMultipartUpload(ctx, bucket, object, metadata, uploadID, opts) + dcache.NewMultipartUpload(ctx, bucket, object, uploadID, opts) return uploadID, err } @@ -971,8 +972,8 @@ func newServerCacheObjects(config CacheConfig) (CacheObjectLayer, error) { GetObjectNInfoFn: func(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (gr *GetObjectReader, err error) { return newObjectLayerFn().GetObjectNInfo(ctx, bucket, object, rs, h, lockType, opts) }, - PutObjectFn: func(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { - return newObjectLayerFn().PutObject(ctx, bucket, object, data, metadata, opts) + PutObjectFn: func(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { + return newObjectLayerFn().PutObject(ctx, bucket, object, data, opts) }, DeleteObjectFn: func(ctx context.Context, bucket, object string) error { return newObjectLayerFn().DeleteObject(ctx, bucket, object) @@ -989,8 +990,8 @@ func newServerCacheObjects(config CacheConfig) (CacheObjectLayer, error) { GetBucketInfoFn: func(ctx context.Context, bucket string) (bucketInfo BucketInfo, err error) { return newObjectLayerFn().GetBucketInfo(ctx, bucket) }, - NewMultipartUploadFn: func(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) { - return newObjectLayerFn().NewMultipartUpload(ctx, bucket, object, metadata, opts) + NewMultipartUploadFn: func(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) { + return newObjectLayerFn().NewMultipartUpload(ctx, bucket, object, opts) }, PutObjectPartFn: func(ctx context.Context, bucket, object, uploadID string, partID int, data *PutObjReader, opts ObjectOptions) (info PartInfo, err error) { return newObjectLayerFn().PutObjectPart(ctx, bucket, object, uploadID, partID, data, opts) diff --git a/cmd/disk-cache_test.go b/cmd/disk-cache_test.go index 2d627d0d6..b21204b85 100644 --- a/cmd/disk-cache_test.go +++ b/cmd/disk-cache_test.go @@ -192,14 +192,13 @@ func TestDiskCache(t *testing.T) { objInfo.ContentType = contentType objInfo.ETag = etag objInfo.UserDefined = httpMeta - opts := ObjectOptions{} - + var opts ObjectOptions byteReader := bytes.NewReader([]byte(content)) hashReader, err := hash.NewReader(byteReader, int64(size), "", "", int64(size)) if err != nil { t.Fatal(err) } - err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), httpMeta, opts) + err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), ObjectOptions{UserDefined: httpMeta}) if err != nil { t.Fatal(err) } @@ -275,12 +274,12 @@ func TestDiskCacheMaxUse(t *testing.T) { t.Fatal(err) } if !cache.diskAvailable(int64(size)) { - err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), httpMeta, opts) + err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), ObjectOptions{UserDefined: httpMeta}) if err != errDiskFull { t.Fatal("Cache max-use limit violated.") } } else { - err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), httpMeta, opts) + err = cache.Put(ctx, bucketName, objectName, NewPutObjReader(hashReader, nil, nil), ObjectOptions{UserDefined: httpMeta}) if err != nil { t.Fatal(err) } diff --git a/cmd/dummy-object-layer_test.go b/cmd/dummy-object-layer_test.go index 869431b6f..a3c5df486 100644 --- a/cmd/dummy-object-layer_test.go +++ b/cmd/dummy-object-layer_test.go @@ -71,7 +71,7 @@ func (api *DummyObjectLayer) GetObjectInfo(ctx context.Context, bucket, object s return } -func (api *DummyObjectLayer) PutObject(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { +func (api *DummyObjectLayer) PutObject(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { return } @@ -87,7 +87,7 @@ func (api *DummyObjectLayer) ListMultipartUploads(ctx context.Context, bucket, p return } -func (api *DummyObjectLayer) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) { +func (api *DummyObjectLayer) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) { return } diff --git a/cmd/encryption-v1.go b/cmd/encryption-v1.go index 23330a548..548a3d7ca 100644 --- a/cmd/encryption-v1.go +++ b/cmd/encryption-v1.go @@ -1171,8 +1171,8 @@ func deriveClientKey(clientKey [32]byte, bucket, object string) [32]byte { return key } -// extract encryption options for pass through to backend in the case of gateway -func extractEncryptionOption(header http.Header, copySource bool, metadata map[string]string) (opts ObjectOptions, err error) { +// set encryption options for pass through to backend in the case of gateway and UserDefined metadata +func getDefaultOpts(header http.Header, copySource bool, metadata map[string]string) (opts ObjectOptions, err error) { var clientKey [32]byte var sse encrypt.ServerSide @@ -1185,7 +1185,7 @@ func extractEncryptionOption(header http.Header, copySource bool, metadata map[s if sse, err = encrypt.NewSSEC(clientKey[:]); err != nil { return } - return ObjectOptions{ServerSideEncryption: encrypt.SSECopy(sse)}, nil + return ObjectOptions{ServerSideEncryption: encrypt.SSECopy(sse), UserDefined: metadata}, nil } return } @@ -1198,16 +1198,16 @@ func extractEncryptionOption(header http.Header, copySource bool, metadata map[s if sse, err = encrypt.NewSSEC(clientKey[:]); err != nil { return } - return ObjectOptions{ServerSideEncryption: sse}, nil + return ObjectOptions{ServerSideEncryption: sse, UserDefined: metadata}, nil } if crypto.S3.IsRequested(header) || (metadata != nil && crypto.S3.IsEncrypted(metadata)) { - return ObjectOptions{ServerSideEncryption: encrypt.NewSSE()}, nil + return ObjectOptions{ServerSideEncryption: encrypt.NewSSE(), UserDefined: metadata}, nil } - return opts, nil + return ObjectOptions{UserDefined: metadata}, nil } // get ObjectOptions for GET calls from encryption headers -func getEncryptionOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { +func getOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { var ( encryption encrypt.ServerSide opts ObjectOptions @@ -1223,30 +1223,32 @@ func getEncryptionOpts(ctx context.Context, r *http.Request, bucket, object stri return ObjectOptions{ServerSideEncryption: encryption}, nil } // default case of passing encryption headers to backend - return extractEncryptionOption(r.Header, false, nil) + return getDefaultOpts(r.Header, false, nil) } -// get ObjectOptions for PUT calls from encryption headers -func putEncryptionOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { +// get ObjectOptions for PUT calls from encryption headers and metadata +func putOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { // In the case of multipart custom format, the metadata needs to be checked in addition to header to see if it // is SSE-S3 encrypted, primarily because S3 protocol does not require SSE-S3 headers in PutObjectPart calls if GlobalGatewaySSE.SSES3() && (crypto.S3.IsRequested(r.Header) || crypto.S3.IsEncrypted(metadata)) { - return ObjectOptions{ServerSideEncryption: encrypt.NewSSE()}, nil + return ObjectOptions{ServerSideEncryption: encrypt.NewSSE(), UserDefined: metadata}, nil } if GlobalGatewaySSE.SSEC() && crypto.SSEC.IsRequested(r.Header) { - return getEncryptionOpts(ctx, r, bucket, object) + opts, err = getOpts(ctx, r, bucket, object) + opts.UserDefined = metadata + return } - // default case of passing encryption headers to backend - return extractEncryptionOption(r.Header, false, metadata) + // default case of passing encryption headers and UserDefined metadata to backend + return getDefaultOpts(r.Header, false, metadata) } -// get ObjectOptions for Copy calls for encryption headers provided on the target side -func copyDstEncryptionOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { - return putEncryptionOpts(ctx, r, bucket, object, metadata) +// get ObjectOptions for Copy calls with encryption headers provided on the target side and source side metadata +func copyDstOpts(ctx context.Context, r *http.Request, bucket, object string, metadata map[string]string) (opts ObjectOptions, err error) { + return putOpts(ctx, r, bucket, object, metadata) } -// get ObjectOptions for Copy calls for encryption headers provided on the source side -func copySrcEncryptionOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { +// get ObjectOptions for Copy calls with encryption headers provided on the source side +func copySrcOpts(ctx context.Context, r *http.Request, bucket, object string) (ObjectOptions, error) { var ( ssec encrypt.ServerSide opts ObjectOptions @@ -1266,5 +1268,5 @@ func copySrcEncryptionOpts(ctx context.Context, r *http.Request, bucket, object } // default case of passing encryption headers to backend - return extractEncryptionOption(r.Header, true, nil) + return getDefaultOpts(r.Header, true, nil) } diff --git a/cmd/encryption-v1_test.go b/cmd/encryption-v1_test.go index b2c9019c7..d08e3be18 100644 --- a/cmd/encryption-v1_test.go +++ b/cmd/encryption-v1_test.go @@ -678,7 +678,7 @@ func TestGetDecryptedRange(t *testing.T) { } } -var extractEncryptionOptionTests = []struct { +var getDefaultOptsTests = []struct { headers http.Header copySource bool metadata map[string]string @@ -741,9 +741,9 @@ var extractEncryptionOptionTests = []struct { err: nil}, // 7 } -func TestExtractEncryptionOptions(t *testing.T) { - for i, test := range extractEncryptionOptionTests { - opts, err := extractEncryptionOption(test.headers, test.copySource, test.metadata) +func TestGetDefaultOpts(t *testing.T) { + for i, test := range getDefaultOptsTests { + opts, err := getDefaultOpts(test.headers, test.copySource, test.metadata) if test.err != err { t.Errorf("Case %d: expected err: %v , actual err: %v", i, test.err, err) } diff --git a/cmd/fs-v1-metadata_test.go b/cmd/fs-v1-metadata_test.go index 0695aa172..5b3bfadc2 100644 --- a/cmd/fs-v1-metadata_test.go +++ b/cmd/fs-v1-metadata_test.go @@ -54,7 +54,7 @@ func TestReadFSMetadata(t *testing.T) { if err := obj.MakeBucketWithLocation(context.Background(), bucketName, ""); err != nil { t.Fatal("Unexpected err: ", err) } - if _, err := obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}); err != nil { + if _, err := obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil { t.Fatal("Unexpected err: ", err) } @@ -89,7 +89,7 @@ func TestWriteFSMetadata(t *testing.T) { if err := obj.MakeBucketWithLocation(context.Background(), bucketName, ""); err != nil { t.Fatal("Unexpected err: ", err) } - if _, err := obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}); err != nil { + if _, err := obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}); err != nil { t.Fatal("Unexpected err: ", err) } diff --git a/cmd/fs-v1-multipart.go b/cmd/fs-v1-multipart.go index 0ac25206f..b64541dc3 100644 --- a/cmd/fs-v1-multipart.go +++ b/cmd/fs-v1-multipart.go @@ -210,7 +210,7 @@ func (fs *FSObjects) ListMultipartUploads(ctx context.Context, bucket, object, k // subsequent request each UUID is unique. // // Implements S3 compatible initiate multipart API. -func (fs *FSObjects) NewMultipartUpload(ctx context.Context, bucket, object string, meta map[string]string, opts ObjectOptions) (string, error) { +func (fs *FSObjects) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (string, error) { if err := checkNewMultipartArgs(ctx, bucket, object, fs); err != nil { return "", toObjectErr(err, bucket) } @@ -230,7 +230,7 @@ func (fs *FSObjects) NewMultipartUpload(ctx context.Context, bucket, object stri // Initialize fs.json values. fsMeta := newFSMetaV1() - fsMeta.Meta = meta + fsMeta.Meta = opts.UserDefined fsMetaBytes, err := json.Marshal(fsMeta) if err != nil { diff --git a/cmd/fs-v1-multipart_test.go b/cmd/fs-v1-multipart_test.go index ae36bb644..c675b40b6 100644 --- a/cmd/fs-v1-multipart_test.go +++ b/cmd/fs-v1-multipart_test.go @@ -42,7 +42,7 @@ func TestFSCleanupMultipartUploadsInRoutine(t *testing.T) { objectName := "object" obj.MakeBucketWithLocation(context.Background(), bucketName, "") - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, objectName, nil, ObjectOptions{}) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{}) if err != nil { t.Fatal("Unexpected err: ", err) } @@ -81,7 +81,7 @@ func TestNewMultipartUploadFaultyDisk(t *testing.T) { // Test with disk removed. os.RemoveAll(disk) - if _, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}); err != nil { + if _, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}); err != nil { if !isSameType(err, BucketNotFound{}) { t.Fatal("Unexpected error ", err) } @@ -105,7 +105,7 @@ func TestPutObjectPartFaultyDisk(t *testing.T) { t.Fatal("Cannot create bucket, err: ", err) } - uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}) + uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}) if err != nil { t.Fatal("Unexpected error ", err) } @@ -136,7 +136,7 @@ func TestCompleteMultipartUploadFaultyDisk(t *testing.T) { t.Fatal("Cannot create bucket, err: ", err) } - uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}) + uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}) if err != nil { t.Fatal("Unexpected error ", err) } @@ -168,7 +168,7 @@ func TestCompleteMultipartUpload(t *testing.T) { t.Fatal("Cannot create bucket, err: ", err) } - uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}) + uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}) if err != nil { t.Fatal("Unexpected error ", err) } @@ -202,7 +202,7 @@ func TestAbortMultipartUpload(t *testing.T) { t.Fatal("Cannot create bucket, err: ", err) } - uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}) + uploadID, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}) if err != nil { t.Fatal("Unexpected error ", err) } @@ -234,7 +234,7 @@ func TestListMultipartUploadsFaultyDisk(t *testing.T) { t.Fatal("Cannot create bucket, err: ", err) } - _, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, map[string]string{"X-Amz-Meta-xid": "3f"}, ObjectOptions{}) + _, err := fs.NewMultipartUpload(context.Background(), bucketName, objectName, ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-xid": "3f"}}) if err != nil { t.Fatal("Unexpected error ", err) } diff --git a/cmd/fs-v1.go b/cmd/fs-v1.go index a27c3e5bb..157923042 100644 --- a/cmd/fs-v1.go +++ b/cmd/fs-v1.go @@ -449,7 +449,7 @@ func (fs *FSObjects) CopyObject(ctx context.Context, srcBucket, srcObject, dstBu // Return the new object info. return fsMeta.ToObjectInfo(srcBucket, srcObject, fi), nil } - objInfo, err := fs.putObject(ctx, dstBucket, dstObject, srcInfo.PutObjReader, srcInfo.UserDefined, dstOpts) + objInfo, err := fs.putObject(ctx, dstBucket, dstObject, srcInfo.PutObjReader, ObjectOptions{ServerSideEncryption: dstOpts.ServerSideEncryption, UserDefined: srcInfo.UserDefined}) if err != nil { return oi, toObjectErr(err, dstBucket, dstObject) } @@ -804,7 +804,7 @@ func (fs *FSObjects) parentDirIsObject(ctx context.Context, bucket, parent strin // until EOF, writes data directly to configured filesystem path. // Additionally writes `fs.json` which carries the necessary metadata // for future object operations. -func (fs *FSObjects) PutObject(ctx context.Context, bucket string, object string, r *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { +func (fs *FSObjects) PutObject(ctx context.Context, bucket string, object string, r *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { if err := checkPutObjectArgs(ctx, bucket, object, fs, r.Size()); err != nil { return ObjectInfo{}, err } @@ -815,16 +815,16 @@ func (fs *FSObjects) PutObject(ctx context.Context, bucket string, object string return objInfo, err } defer objectLock.Unlock() - return fs.putObject(ctx, bucket, object, r, metadata, opts) + return fs.putObject(ctx, bucket, object, r, opts) } // putObject - wrapper for PutObject -func (fs *FSObjects) putObject(ctx context.Context, bucket string, object string, r *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { +func (fs *FSObjects) putObject(ctx context.Context, bucket string, object string, r *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, retErr error) { data := r.Reader // No metadata is set, allocate a new one. meta := make(map[string]string) - for k, v := range metadata { + for k, v := range opts.UserDefined { meta[k] = v } var err error diff --git a/cmd/fs-v1_test.go b/cmd/fs-v1_test.go index a23ebb983..973f1f796 100644 --- a/cmd/fs-v1_test.go +++ b/cmd/fs-v1_test.go @@ -40,7 +40,7 @@ func TestFSParentDirIsObject(t *testing.T) { } objectContent := "12345" objInfo, err := obj.PutObject(context.Background(), bucketName, objectName, - mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), nil, ObjectOptions{}) + mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{}) if err != nil { t.Fatal(err) } @@ -124,7 +124,7 @@ func TestFSShutdown(t *testing.T) { objectContent := "12345" obj.MakeBucketWithLocation(context.Background(), bucketName, "") - obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), nil, ObjectOptions{}) + obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{}) return fs, disk } @@ -203,7 +203,7 @@ func TestFSPutObject(t *testing.T) { } // With a regular object. - _, err := obj.PutObject(context.Background(), bucketName+"non-existent", objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}) + _, err := obj.PutObject(context.Background(), bucketName+"non-existent", objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}) if err == nil { t.Fatal("Unexpected should fail here, bucket doesn't exist") } @@ -212,7 +212,7 @@ func TestFSPutObject(t *testing.T) { } // With a directory object. - _, err = obj.PutObject(context.Background(), bucketName+"non-existent", objectName+"/", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName+"non-existent", objectName+"/", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), ObjectOptions{}) if err == nil { t.Fatal("Unexpected should fail here, bucket doesn't exist") } @@ -220,11 +220,11 @@ func TestFSPutObject(t *testing.T) { t.Fatalf("Expected error type BucketNotFound, got %#v", err) } - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}) if err != nil { t.Fatal(err) } - _, err = obj.PutObject(context.Background(), bucketName, objectName+"/1", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName+"/1", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}) if err == nil { t.Fatal("Unexpected should fail here, backend corruption occurred") } @@ -239,7 +239,7 @@ func TestFSPutObject(t *testing.T) { } } - _, err = obj.PutObject(context.Background(), bucketName, objectName+"/1/", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName+"/1/", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), 0, "", ""), ObjectOptions{}) if err == nil { t.Fatal("Unexpected should fail here, backned corruption occurred") } @@ -267,7 +267,7 @@ func TestFSDeleteObject(t *testing.T) { objectName := "object" obj.MakeBucketWithLocation(context.Background(), bucketName, "") - obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}) + obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}) // Test with invalid bucket name if err := fs.DeleteObject(context.Background(), "fo", objectName); !isSameType(err, BucketNameInvalid{}) { diff --git a/cmd/gateway-unsupported.go b/cmd/gateway-unsupported.go index cabd8eeb7..1e12f08d7 100644 --- a/cmd/gateway-unsupported.go +++ b/cmd/gateway-unsupported.go @@ -33,7 +33,7 @@ func (a GatewayUnsupported) ListMultipartUploads(ctx context.Context, bucket str } // NewMultipartUpload upload object in multiple parts -func (a GatewayUnsupported) NewMultipartUpload(ctx context.Context, bucket string, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) { +func (a GatewayUnsupported) NewMultipartUpload(ctx context.Context, bucket string, object string, opts ObjectOptions) (uploadID string, err error) { return "", NotImplemented{} } diff --git a/cmd/gateway/azure/gateway-azure.go b/cmd/gateway/azure/gateway-azure.go index 622a192b1..925bfb1de 100644 --- a/cmd/gateway/azure/gateway-azure.go +++ b/cmd/gateway/azure/gateway-azure.go @@ -735,11 +735,11 @@ func (a *azureObjects) GetObjectInfo(ctx context.Context, bucket, object string, // PutObject - Create a new blob with the incoming data, // uses Azure equivalent CreateBlockBlobFromReader. -func (a *azureObjects) PutObject(ctx context.Context, bucket, object string, r *minio.PutObjReader, metadata map[string]string, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { +func (a *azureObjects) PutObject(ctx context.Context, bucket, object string, r *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { data := r.Reader if data.Size() < azureBlockSize/10 { blob := a.client.GetContainerReference(bucket).GetBlobReference(object) - blob.Metadata, blob.Properties, err = s3MetaToAzureProperties(ctx, metadata) + blob.Metadata, blob.Properties, err = s3MetaToAzureProperties(ctx, opts.UserDefined) if err = blob.CreateBlockBlobFromReader(data, nil); err != nil { return objInfo, azureToObjectError(err, bucket, object) } @@ -803,13 +803,13 @@ func (a *azureObjects) PutObject(ctx context.Context, bucket, object string, r * return objInfo, azureToObjectError(err, bucket, object) } - if len(metadata) == 0 { - metadata = map[string]string{} + if len(opts.UserDefined) == 0 { + opts.UserDefined = map[string]string{} } // Save md5sum for future processing on the object. - metadata["x-amz-meta-md5sum"] = r.MD5CurrentHexString() - objBlob.Metadata, objBlob.Properties, err = s3MetaToAzureProperties(ctx, metadata) + opts.UserDefined["x-amz-meta-md5sum"] = hex.EncodeToString(data.MD5Current()) + objBlob.Metadata, objBlob.Properties, err = s3MetaToAzureProperties(ctx, opts.UserDefined) if err != nil { return objInfo, azureToObjectError(err, bucket, object) } @@ -910,7 +910,7 @@ func (a *azureObjects) checkUploadIDExists(ctx context.Context, bucketName, obje } // NewMultipartUpload - Use Azure equivalent CreateBlockBlob. -func (a *azureObjects) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts minio.ObjectOptions) (uploadID string, err error) { +func (a *azureObjects) NewMultipartUpload(ctx context.Context, bucket, object string, opts minio.ObjectOptions) (uploadID string, err error) { uploadID, err = getAzureUploadID() if err != nil { logger.LogIf(ctx, err) @@ -919,7 +919,7 @@ func (a *azureObjects) NewMultipartUpload(ctx context.Context, bucket, object st metadataObject := getAzureMetadataObjectName(object, uploadID) var jsonData []byte - if jsonData, err = json.Marshal(azureMultipartMetadata{Name: object, Metadata: metadata}); err != nil { + if jsonData, err = json.Marshal(azureMultipartMetadata{Name: object, Metadata: opts.UserDefined}); err != nil { logger.LogIf(ctx, err) return "", err } diff --git a/cmd/gateway/gcs/gateway-gcs.go b/cmd/gateway/gcs/gateway-gcs.go index a385a67d4..720ec14b5 100644 --- a/cmd/gateway/gcs/gateway-gcs.go +++ b/cmd/gateway/gcs/gateway-gcs.go @@ -877,7 +877,7 @@ func (l *gcsGateway) GetObjectInfo(ctx context.Context, bucket string, object st } // PutObject - Create a new object with the incoming data, -func (l *gcsGateway) PutObject(ctx context.Context, bucket string, key string, r *minio.PutObjReader, metadata map[string]string, opts minio.ObjectOptions) (minio.ObjectInfo, error) { +func (l *gcsGateway) PutObject(ctx context.Context, bucket string, key string, r *minio.PutObjReader, opts minio.ObjectOptions) (minio.ObjectInfo, error) { data := r.Reader // if we want to mimic S3 behavior exactly, we need to verify if bucket exists first, @@ -895,7 +895,7 @@ func (l *gcsGateway) PutObject(ctx context.Context, bucket string, key string, r if data.Size() < int64(w.ChunkSize) { w.ChunkSize = 0 } - applyMetadataToGCSAttrs(metadata, &w.ObjectAttrs) + applyMetadataToGCSAttrs(opts.UserDefined, &w.ObjectAttrs) if _, err := io.Copy(w, data); err != nil { // Close the object writer upon error. @@ -947,7 +947,7 @@ func (l *gcsGateway) DeleteObject(ctx context.Context, bucket string, object str } // NewMultipartUpload - upload object in multiple parts -func (l *gcsGateway) NewMultipartUpload(ctx context.Context, bucket string, key string, metadata map[string]string, o minio.ObjectOptions) (uploadID string, err error) { +func (l *gcsGateway) NewMultipartUpload(ctx context.Context, bucket string, key string, o minio.ObjectOptions) (uploadID string, err error) { // generate new uploadid uploadID = minio.MustGetUUID() @@ -957,7 +957,7 @@ func (l *gcsGateway) NewMultipartUpload(ctx context.Context, bucket string, key w := l.client.Bucket(bucket).Object(meta).NewWriter(ctx) defer w.Close() - applyMetadataToGCSAttrs(metadata, &w.ObjectAttrs) + applyMetadataToGCSAttrs(o.UserDefined, &w.ObjectAttrs) if err = json.NewEncoder(w).Encode(gcsMultipartMetaV1{ gcsMinioMultipartMetaCurrentVersion, diff --git a/cmd/gateway/oss/gateway-oss.go b/cmd/gateway/oss/gateway-oss.go index ba957433e..21a62c6aa 100644 --- a/cmd/gateway/oss/gateway-oss.go +++ b/cmd/gateway/oss/gateway-oss.go @@ -656,10 +656,10 @@ func ossPutObject(ctx context.Context, client *oss.Client, bucket, object string } // PutObject creates a new object with the incoming data. -func (l *ossObjects) PutObject(ctx context.Context, bucket, object string, r *minio.PutObjReader, metadata map[string]string, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { +func (l *ossObjects) PutObject(ctx context.Context, bucket, object string, r *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { data := r.Reader - return ossPutObject(ctx, l.Client, bucket, object, data, metadata) + return ossPutObject(ctx, l.Client, bucket, object, data, opts.UserDefined) } // CopyObject copies an object from source bucket to a destination bucket. @@ -753,7 +753,7 @@ func (l *ossObjects) ListMultipartUploads(ctx context.Context, bucket, prefix, k } // NewMultipartUpload upload object in multiple parts. -func (l *ossObjects) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, o minio.ObjectOptions) (uploadID string, err error) { +func (l *ossObjects) NewMultipartUpload(ctx context.Context, bucket, object string, o minio.ObjectOptions) (uploadID string, err error) { bkt, err := l.Client.Bucket(bucket) if err != nil { logger.LogIf(ctx, err) @@ -761,7 +761,7 @@ func (l *ossObjects) NewMultipartUpload(ctx context.Context, bucket, object stri } // Build OSS metadata - opts, err := appendS3MetaToOSSOptions(ctx, nil, metadata) + opts, err := appendS3MetaToOSSOptions(ctx, nil, o.UserDefined) if err != nil { return uploadID, ossToObjectError(err, bucket, object) } diff --git a/cmd/gateway/s3/gateway-s3-sse.go b/cmd/gateway/s3/gateway-s3-sse.go index 1c6fff2fc..3b51285c2 100644 --- a/cmd/gateway/s3/gateway-s3-sse.go +++ b/cmd/gateway/s3/gateway-s3-sse.go @@ -236,7 +236,7 @@ func (l *s3EncObjects) writeGWMetadata(ctx context.Context, bucket, metaFileName logger.LogIf(ctx, err) return err } - _, err = l.s3Objects.PutObject(ctx, bucket, metaFileName, reader, map[string]string{}, o) + _, err = l.s3Objects.PutObject(ctx, bucket, metaFileName, reader, o) return err } @@ -373,7 +373,8 @@ func (l *s3EncObjects) CopyObject(ctx context.Context, srcBucket string, srcObje return gwMeta.ToObjectInfo(dstBucket, dstObject), nil } } - return l.PutObject(ctx, dstBucket, dstObject, srcInfo.PutObjReader, srcInfo.UserDefined, d) + dstOpts := minio.ObjectOptions{ServerSideEncryption: d.ServerSideEncryption, UserDefined: srcInfo.UserDefined} + return l.PutObject(ctx, dstBucket, dstObject, srcInfo.PutObjReader, dstOpts) } // DeleteObject deletes a blob in bucket @@ -406,23 +407,24 @@ func (l *s3EncObjects) ListMultipartUploads(ctx context.Context, bucket string, } // NewMultipartUpload uploads object in multiple parts -func (l *s3EncObjects) NewMultipartUpload(ctx context.Context, bucket string, object string, metadata map[string]string, o minio.ObjectOptions) (uploadID string, err error) { - var opts minio.ObjectOptions - if o.ServerSideEncryption != nil && - ((minio.GlobalGatewaySSE.SSEC() && o.ServerSideEncryption.Type() == encrypt.SSEC) || - (minio.GlobalGatewaySSE.SSES3() && o.ServerSideEncryption.Type() == encrypt.S3)) { - opts = o - } +func (l *s3EncObjects) NewMultipartUpload(ctx context.Context, bucket string, object string, o minio.ObjectOptions) (uploadID string, err error) { + var sseOpts encrypt.ServerSide if o.ServerSideEncryption == nil { - return l.s3Objects.NewMultipartUpload(ctx, bucket, object, metadata, opts) + return l.s3Objects.NewMultipartUpload(ctx, bucket, object, minio.ObjectOptions{UserDefined: o.UserDefined}) } - uploadID, err = l.s3Objects.NewMultipartUpload(ctx, bucket, getGWContentPath(object), map[string]string{}, opts) + // Decide if sse options needed to be passed to backend + if (minio.GlobalGatewaySSE.SSEC() && o.ServerSideEncryption.Type() == encrypt.SSEC) || + (minio.GlobalGatewaySSE.SSES3() && o.ServerSideEncryption.Type() == encrypt.S3) { + sseOpts = o.ServerSideEncryption + } + + uploadID, err = l.s3Objects.NewMultipartUpload(ctx, bucket, getGWContentPath(object), minio.ObjectOptions{ServerSideEncryption: sseOpts}) if err != nil { return } // Create uploadID and write a temporary dare.meta object under object/uploadID prefix gwmeta := newGWMetaV1() - gwmeta.Meta = metadata + gwmeta.Meta = o.UserDefined gwmeta.Stat.ModTime = time.Now().UTC() err = l.writeGWMetadata(ctx, bucket, getTmpDareMetaPath(object, uploadID), gwmeta, minio.ObjectOptions{}) if err != nil { @@ -432,30 +434,28 @@ func (l *s3EncObjects) NewMultipartUpload(ctx context.Context, bucket string, ob } // PutObject creates a new object with the incoming data, -func (l *s3EncObjects) PutObject(ctx context.Context, bucket string, object string, data *minio.PutObjReader, metadata map[string]string, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { - var s3Opts minio.ObjectOptions +func (l *s3EncObjects) PutObject(ctx context.Context, bucket string, object string, data *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { + var sseOpts encrypt.ServerSide + // Decide if sse options needed to be passed to backend if opts.ServerSideEncryption != nil && ((minio.GlobalGatewaySSE.SSEC() && opts.ServerSideEncryption.Type() == encrypt.SSEC) || (minio.GlobalGatewaySSE.SSES3() && opts.ServerSideEncryption.Type() == encrypt.S3)) { - s3Opts = opts + sseOpts = opts.ServerSideEncryption } if opts.ServerSideEncryption == nil { defer l.deleteGWMetadata(ctx, bucket, getDareMetaPath(object)) defer l.DeleteObject(ctx, bucket, getGWContentPath(object)) - return l.s3Objects.PutObject(ctx, bucket, object, data, metadata, s3Opts) + return l.s3Objects.PutObject(ctx, bucket, object, data, minio.ObjectOptions{UserDefined: opts.UserDefined}) } - oi, err := l.s3Objects.PutObject(ctx, bucket, getGWContentPath(object), data, map[string]string{}, s3Opts) + oi, err := l.s3Objects.PutObject(ctx, bucket, getGWContentPath(object), data, minio.ObjectOptions{ServerSideEncryption: sseOpts}) if err != nil { return objInfo, minio.ErrorRespToObjectError(err) } gwMeta := newGWMetaV1() gwMeta.Meta = make(map[string]string) - for k, v := range oi.UserDefined { - gwMeta.Meta[k] = v - } - for k, v := range metadata { + for k, v := range opts.UserDefined { gwMeta.Meta[k] = v } encMD5 := data.MD5CurrentHexString() diff --git a/cmd/gateway/s3/gateway-s3.go b/cmd/gateway/s3/gateway-s3.go index 680835bd0..841571ef5 100644 --- a/cmd/gateway/s3/gateway-s3.go +++ b/cmd/gateway/s3/gateway-s3.go @@ -448,15 +448,15 @@ func (l *s3Objects) GetObjectInfo(ctx context.Context, bucket string, object str } // PutObject creates a new object with the incoming data, -func (l *s3Objects) PutObject(ctx context.Context, bucket string, object string, r *minio.PutObjReader, metadata map[string]string, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { +func (l *s3Objects) PutObject(ctx context.Context, bucket string, object string, r *minio.PutObjReader, opts minio.ObjectOptions) (objInfo minio.ObjectInfo, err error) { data := r.Reader - oi, err := l.Client.PutObject(bucket, object, data, data.Size(), data.MD5Base64String(), data.SHA256HexString(), minio.ToMinioClientMetadata(metadata), opts.ServerSideEncryption) + oi, err := l.Client.PutObject(bucket, object, data, data.Size(), data.MD5Base64String(), data.SHA256HexString(), minio.ToMinioClientMetadata(opts.UserDefined), opts.ServerSideEncryption) if err != nil { return objInfo, minio.ErrorRespToObjectError(err, bucket, object) } // On success, populate the key & metadata so they are present in the notification oi.Key = object - oi.Metadata = minio.ToMinioClientObjectInfoMetadata(metadata) + oi.Metadata = minio.ToMinioClientObjectInfoMetadata(opts.UserDefined) return minio.FromMinioClientObjectInfo(bucket, oi), nil } @@ -508,9 +508,9 @@ func (l *s3Objects) ListMultipartUploads(ctx context.Context, bucket string, pre } // NewMultipartUpload upload object in multiple parts -func (l *s3Objects) NewMultipartUpload(ctx context.Context, bucket string, object string, metadata map[string]string, o minio.ObjectOptions) (uploadID string, err error) { +func (l *s3Objects) NewMultipartUpload(ctx context.Context, bucket string, object string, o minio.ObjectOptions) (uploadID string, err error) { // Create PutObject options - opts := miniogo.PutObjectOptions{UserMetadata: metadata, ServerSideEncryption: o.ServerSideEncryption} + opts := miniogo.PutObjectOptions{UserMetadata: o.UserDefined, ServerSideEncryption: o.ServerSideEncryption} uploadID, err = l.Client.NewMultipartUpload(bucket, object, opts) if err != nil { return uploadID, minio.ErrorRespToObjectError(err, bucket, object) diff --git a/cmd/object-api-deleteobject_test.go b/cmd/object-api-deleteobject_test.go index 5eadc2c58..e820dbfd2 100644 --- a/cmd/object-api-deleteobject_test.go +++ b/cmd/object-api-deleteobject_test.go @@ -93,7 +93,7 @@ func testDeleteObject(obj ObjectLayer, instanceType string, t TestErrHandler) { for _, object := range testCase.objectToUploads { md5Bytes := md5.Sum([]byte(object.content)) _, err = obj.PutObject(context.Background(), testCase.bucketName, object.name, mustGetPutObjReader(t, bytes.NewBufferString(object.content), - int64(len(object.content)), hex.EncodeToString(md5Bytes[:]), ""), nil, ObjectOptions{}) + int64(len(object.content)), hex.EncodeToString(md5Bytes[:]), ""), ObjectOptions{}) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } diff --git a/cmd/object-api-getobject_test.go b/cmd/object-api-getobject_test.go index ee8b3a79f..cbcbbddfe 100644 --- a/cmd/object-api-getobject_test.go +++ b/cmd/object-api-getobject_test.go @@ -75,7 +75,7 @@ func testGetObject(obj ObjectLayer, instanceType string, t TestErrHandler) { // iterate through the above set of inputs and upkoad the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), input.metaData, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -220,7 +220,7 @@ func testGetObjectPermissionDenied(obj ObjectLayer, instanceType string, disks [ // iterate through the above set of inputs and upkoad the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), input.metaData, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -333,7 +333,7 @@ func testGetObjectDiskNotFound(obj ObjectLayer, instanceType string, disks []str // iterate through the above set of inputs and upkoad the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), input.metaData, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) diff --git a/cmd/object-api-getobjectinfo_test.go b/cmd/object-api-getobjectinfo_test.go index d98a5d1cb..64b39dc28 100644 --- a/cmd/object-api-getobjectinfo_test.go +++ b/cmd/object-api-getobjectinfo_test.go @@ -35,13 +35,13 @@ func testGetObjectInfo(obj ObjectLayer, instanceType string, t TestErrHandler) { t.Fatalf("%s : %s", instanceType, err.Error()) } opts := ObjectOptions{} - _, err = obj.PutObject(context.Background(), "test-getobjectinfo", "Asia/asiapics.jpg", mustGetPutObjReader(t, bytes.NewBufferString("asiapics"), int64(len("asiapics")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "test-getobjectinfo", "Asia/asiapics.jpg", mustGetPutObjReader(t, bytes.NewBufferString("asiapics"), int64(len("asiapics")), "", ""), opts) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } // Put an empty directory - _, err = obj.PutObject(context.Background(), "test-getobjectinfo", "Asia/empty-dir/", mustGetPutObjReader(t, bytes.NewBufferString(""), int64(len("")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "test-getobjectinfo", "Asia/empty-dir/", mustGetPutObjReader(t, bytes.NewBufferString(""), int64(len("")), "", ""), opts) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } diff --git a/cmd/object-api-interface.go b/cmd/object-api-interface.go index 45945b1e0..ef0b8cb1b 100644 --- a/cmd/object-api-interface.go +++ b/cmd/object-api-interface.go @@ -29,6 +29,7 @@ import ( // ObjectOptions represents object options for ObjectLayer operations type ObjectOptions struct { ServerSideEncryption encrypt.ServerSide + UserDefined map[string]string } // LockType represents required locking for ObjectLayer operations @@ -65,13 +66,13 @@ type ObjectLayer interface { GetObjectNInfo(ctx context.Context, bucket, object string, rs *HTTPRangeSpec, h http.Header, lockType LockType, opts ObjectOptions) (reader *GetObjectReader, err error) GetObject(ctx context.Context, bucket, object string, startOffset int64, length int64, writer io.Writer, etag string, opts ObjectOptions) (err error) GetObjectInfo(ctx context.Context, bucket, object string, opts ObjectOptions) (objInfo ObjectInfo, err error) - PutObject(ctx context.Context, bucket, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) + PutObject(ctx context.Context, bucket, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) CopyObject(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, srcInfo ObjectInfo, srcOpts, dstOpts ObjectOptions) (objInfo ObjectInfo, err error) DeleteObject(ctx context.Context, bucket, object string) error // Multipart operations. ListMultipartUploads(ctx context.Context, bucket, prefix, keyMarker, uploadIDMarker, delimiter string, maxUploads int) (result ListMultipartsInfo, err error) - NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) + NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) CopyObjectPart(ctx context.Context, srcBucket, srcObject, destBucket, destObject string, uploadID string, partID int, startOffset int64, length int64, srcInfo ObjectInfo, srcOpts, dstOpts ObjectOptions) (info PartInfo, err error) PutObjectPart(ctx context.Context, bucket, object, uploadID string, partID int, data *PutObjReader, opts ObjectOptions) (info PartInfo, err error) diff --git a/cmd/object-api-listobjects_test.go b/cmd/object-api-listobjects_test.go index e219254d9..f12e6d39d 100644 --- a/cmd/object-api-listobjects_test.go +++ b/cmd/object-api-listobjects_test.go @@ -71,7 +71,7 @@ func testListObjects(obj ObjectLayer, instanceType string, t TestErrHandler) { for _, object := range testObjects { md5Bytes := md5.Sum([]byte(object.content)) _, err = obj.PutObject(context.Background(), testBuckets[0], object.name, mustGetPutObjReader(t, bytes.NewBufferString(object.content), - int64(len(object.content)), hex.EncodeToString(md5Bytes[:]), ""), object.meta, ObjectOptions{}) + int64(len(object.content)), hex.EncodeToString(md5Bytes[:]), ""), ObjectOptions{UserDefined: object.meta}) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } @@ -625,7 +625,7 @@ func BenchmarkListObjects(b *testing.B) { // Insert objects to be listed and benchmarked later. for i := 0; i < 20000; i++ { key := "obj" + strconv.Itoa(i) - _, err = obj.PutObject(context.Background(), bucket, key, mustGetPutObjReader(b, bytes.NewBufferString(key), int64(len(key)), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucket, key, mustGetPutObjReader(b, bytes.NewBufferString(key), int64(len(key)), "", ""), ObjectOptions{}) if err != nil { b.Fatal(err) } diff --git a/cmd/object-api-multipart_test.go b/cmd/object-api-multipart_test.go index 48ef8f92a..ab701ff72 100644 --- a/cmd/object-api-multipart_test.go +++ b/cmd/object-api-multipart_test.go @@ -41,14 +41,14 @@ func testObjectNewMultipartUpload(obj ObjectLayer, instanceType string, t TestEr bucket := "minio-bucket" object := "minio-object" opts := ObjectOptions{} - _, err := obj.NewMultipartUpload(context.Background(), "--", object, nil, opts) + _, err := obj.NewMultipartUpload(context.Background(), "--", object, opts) if err == nil { t.Fatalf("%s: Expected to fail since bucket name is invalid.", instanceType) } errMsg := "Bucket not found: minio-bucket" // opearation expected to fail since the bucket on which NewMultipartUpload is being initiated doesn't exist. - _, err = obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + _, err = obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err == nil { t.Fatalf("%s: Expected to fail since the NewMultipartUpload is intialized on a non-existent bucket.", instanceType) } @@ -63,12 +63,12 @@ func testObjectNewMultipartUpload(obj ObjectLayer, instanceType string, t TestEr t.Fatalf("%s : %s", instanceType, err.Error()) } - _, err = obj.NewMultipartUpload(context.Background(), bucket, "\\", nil, opts) + _, err = obj.NewMultipartUpload(context.Background(), bucket, "\\", opts) if err == nil { t.Fatalf("%s: Expected to fail since object name is invalid.", instanceType) } - uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } @@ -102,7 +102,7 @@ func testObjectAbortMultipartUpload(obj ObjectLayer, instanceType string, t Test t.Fatalf("%s : %s", instanceType, err.Error()) } - uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } @@ -148,7 +148,7 @@ func testObjectAPIIsUploadIDExists(obj ObjectLayer, instanceType string, t TestE t.Fatalf("%s : %s", instanceType, err.Error()) } - _, err = obj.NewMultipartUpload(context.Background(), bucket, object, nil, ObjectOptions{}) + _, err = obj.NewMultipartUpload(context.Background(), bucket, object, ObjectOptions{}) if err != nil { t.Fatalf("%s : %s", instanceType, err.Error()) } @@ -184,7 +184,7 @@ func testPutObjectPartDiskNotFound(obj ObjectLayer, instanceType string, disks [ } // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], nil, ObjectOptions{}) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], ObjectOptions{}) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -264,7 +264,7 @@ func testObjectAPIPutObjectPart(obj ObjectLayer, instanceType string, t TestErrH t.Fatalf("%s : %s", instanceType, err.Error()) } // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -400,7 +400,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan t.Fatalf("%s : %s", instanceType, err.Error()) } // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -420,7 +420,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan for i := 0; i < 3; i++ { // Initiate Multipart Upload on bucketNames[1] for the same object 3 times. // Used to test the listing for the case of multiple uploadID's for a given object. - uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[1], objectNames[0], nil, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[1], objectNames[0], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -442,7 +442,7 @@ func testListMultipartUploads(obj ObjectLayer, instanceType string, t TestErrHan // Used to test the listing for the case of multiple objects for a given bucket. for i := 0; i < 6; i++ { var uploadID string - uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[2], objectNames[i], nil, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[2], objectNames[i], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -1275,7 +1275,7 @@ func testListObjectPartsDiskNotFound(obj ObjectLayer, instanceType string, disks } opts := ObjectOptions{} // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -1519,7 +1519,7 @@ func testListObjectParts(obj ObjectLayer, instanceType string, t TestErrHandler) t.Fatalf("%s : %s", instanceType, err.Error()) } // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -1764,9 +1764,8 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T // Failed to create newbucket, abort. t.Fatalf("%s : %s", instanceType, err) } - opts := ObjectOptions{} // Initiate Multipart Upload on the above created bucket. - uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], map[string]string{"X-Amz-Meta-Id": "id"}, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], ObjectOptions{UserDefined: map[string]string{"X-Amz-Meta-Id": "id"}}) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err) @@ -1799,6 +1798,7 @@ func testObjectCompleteMultipartUpload(obj ObjectLayer, instanceType string, t T {bucketNames[0], objectNames[0], uploadIDs[0], 6, string(validPart), validPartMD5, int64(len(string(validPart)))}, } sha256sum := "" + var opts ObjectOptions // Iterating over creatPartCases to generate multipart chunks. for _, part := range parts { _, err = obj.PutObjectPart(context.Background(), part.bucketName, part.objName, part.uploadID, part.PartID, mustGetPutObjReader(t, bytes.NewBufferString(part.inputReaderData), part.intputDataSize, part.inputMd5, sha256sum), opts) diff --git a/cmd/object-api-putobject_test.go b/cmd/object-api-putobject_test.go index 6868ff647..ac7f0347e 100644 --- a/cmd/object-api-putobject_test.go +++ b/cmd/object-api-putobject_test.go @@ -172,7 +172,7 @@ func testObjectAPIPutObject(obj ObjectLayer, instanceType string, t TestErrHandl } for i, testCase := range testCases { - objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], testCase.inputSHA256), testCase.inputMeta, ObjectOptions{}) + objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], testCase.inputSHA256), ObjectOptions{UserDefined: testCase.inputMeta}) if actualErr != nil && testCase.expectedError == nil { t.Errorf("Test %d: %s: Expected to pass, but failed with: error %s.", i+1, instanceType, actualErr.Error()) } @@ -245,7 +245,7 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di sha256sum := "" for i, testCase := range testCases { - objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), testCase.inputMeta, ObjectOptions{}) + objInfo, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta}) if actualErr != nil && testCase.shouldPass { t.Errorf("Test %d: %s: Expected to pass, but failed with: %s.", i+1, instanceType, actualErr.Error()) } @@ -294,7 +294,7 @@ func testObjectAPIPutObjectDiskNotFound(obj ObjectLayer, instanceType string, di InsufficientWriteQuorum{}, } - _, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), testCase.inputMeta, ObjectOptions{}) + _, actualErr := obj.PutObject(context.Background(), testCase.bucketName, testCase.objName, mustGetPutObjReader(t, bytes.NewReader(testCase.inputData), testCase.intputDataSize, testCase.inputMeta["etag"], sha256sum), ObjectOptions{UserDefined: testCase.inputMeta}) if actualErr != nil && testCase.shouldPass { t.Errorf("Test %d: %s: Expected to pass, but failed with: %s.", len(testCases)+1, instanceType, actualErr.Error()) } @@ -326,7 +326,7 @@ func testObjectAPIPutObjectStaleFiles(obj ObjectLayer, instanceType string, disk data := []byte("hello, world") // Create object. - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{}) if err != nil { // Failed to create object, abort. t.Fatalf("%s : %s", instanceType, err.Error()) @@ -359,7 +359,7 @@ func testObjectAPIMultipartPutObjectStaleFiles(obj ObjectLayer, instanceType str } opts := ObjectOptions{} // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) diff --git a/cmd/object-handlers.go b/cmd/object-handlers.go index bfadf289f..3cb36da1f 100644 --- a/cmd/object-handlers.go +++ b/cmd/object-handlers.go @@ -102,7 +102,7 @@ func (api objectAPIHandlers) SelectObjectContentHandler(w http.ResponseWriter, r object := vars["object"] // get gateway encryption options - opts, err := getEncryptionOpts(ctx, r, bucket, object) + opts, err := getOpts(ctx, r, bucket, object) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -257,7 +257,7 @@ func (api objectAPIHandlers) GetObjectHandler(w http.ResponseWriter, r *http.Req } // get gateway encryption options - opts, err := getEncryptionOpts(ctx, r, bucket, object) + opts, err := getOpts(ctx, r, bucket, object) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -441,7 +441,7 @@ func (api objectAPIHandlers) HeadObjectHandler(w http.ResponseWriter, r *http.Re getObjectInfo = api.CacheAPI().GetObjectInfo } - opts, err := getEncryptionOpts(ctx, r, bucket, object) + opts, err := getOpts(ctx, r, bucket, object) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -707,7 +707,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re } var srcOpts, dstOpts ObjectOptions - srcOpts, err := copySrcEncryptionOpts(ctx, r, srcBucket, srcObject) + srcOpts, err := copySrcOpts(ctx, r, srcBucket, srcObject) if err != nil { logger.LogIf(ctx, err) writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) @@ -719,7 +719,7 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re if getSSE != srcOpts.ServerSideEncryption { getOpts.ServerSideEncryption = getSSE } - dstOpts, err = copyDstEncryptionOpts(ctx, r, dstBucket, dstObject, nil) + dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, nil) if err != nil { logger.LogIf(ctx, err) writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) @@ -1239,7 +1239,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req } // get gateway encryption options var opts ObjectOptions - opts, err = putEncryptionOpts(ctx, r, bucket, object, nil) + opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -1279,7 +1279,7 @@ func (api objectAPIHandlers) PutObjectHandler(w http.ResponseWriter, r *http.Req } // Create the object.. - objInfo, err := putObject(ctx, bucket, object, pReader, metadata, opts) + objInfo, err := putObject(ctx, bucket, object, pReader, opts) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1371,7 +1371,7 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r var opts ObjectOptions var err error - opts, err = putEncryptionOpts(ctx, r, bucket, object, nil) + opts, err = putOpts(ctx, r, bucket, object, nil) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -1428,11 +1428,16 @@ func (api objectAPIHandlers) NewMultipartUploadHandler(w http.ResponseWriter, r metadata[ReservedMetadataPrefix+"compression"] = compressionAlgorithmV1 } + opts, err = putOpts(ctx, r, bucket, object, metadata) + if err != nil { + writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) + return + } newMultipartUpload := objectAPI.NewMultipartUpload if api.CacheAPI() != nil && !hasServerSideEncryptionHeader(r.Header) { newMultipartUpload = api.CacheAPI().NewMultipartUpload } - uploadID, err := newMultipartUpload(ctx, bucket, object, metadata, opts) + uploadID, err := newMultipartUpload(ctx, bucket, object, opts) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1531,7 +1536,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt } var srcOpts, dstOpts ObjectOptions - srcOpts, err = copySrcEncryptionOpts(ctx, r, srcBucket, srcObject) + srcOpts, err = copySrcOpts(ctx, r, srcBucket, srcObject) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1541,7 +1546,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt if srcOpts.ServerSideEncryption != nil { getOpts.ServerSideEncryption = encrypt.SSE(srcOpts.ServerSideEncryption) } - dstOpts, err = copyDstEncryptionOpts(ctx, r, dstBucket, dstObject, nil) + dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, nil) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1669,7 +1674,7 @@ func (api objectAPIHandlers) CopyObjectPartHandler(w http.ResponseWriter, r *htt return } li.UserDefined = CleanMinioInternalMetadataKeys(li.UserDefined) - dstOpts, err = copyDstEncryptionOpts(ctx, r, dstBucket, dstObject, li.UserDefined) + dstOpts, err = copyDstOpts(ctx, r, dstBucket, dstObject, li.UserDefined) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1863,7 +1868,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http // get encryption options var opts ObjectOptions if crypto.SSEC.IsRequested(r.Header) { - opts, err = putEncryptionOpts(ctx, r, bucket, object, nil) + opts, err = putOpts(ctx, r, bucket, object, nil) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return @@ -1938,7 +1943,7 @@ func (api objectAPIHandlers) PutObjectPartHandler(w http.ResponseWriter, r *http } isEncrypted = true // to detect SSE-S3 encryption - opts, err = putEncryptionOpts(ctx, r, bucket, object, li.UserDefined) + opts, err = putOpts(ctx, r, bucket, object, li.UserDefined) if err != nil { writeErrorResponse(w, toAPIErrorCode(ctx, err), r.URL, guessIsBrowserReq(r)) return diff --git a/cmd/object-handlers_test.go b/cmd/object-handlers_test.go index 02e9e17ba..af7db210c 100644 --- a/cmd/object-handlers_test.go +++ b/cmd/object-handlers_test.go @@ -85,7 +85,7 @@ func testAPIHeadObjectHandler(obj ObjectLayer, instanceType, bucketName string, // iterate through the above set of inputs and upload the object. for i, input := range putObjectInputs { // uploading the object. - _, err := obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, ObjectOptions{}) + _, err := obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -357,7 +357,7 @@ func testAPIGetObjectHandler(obj ObjectLayer, instanceType, bucketName string, a // iterate through the above set of inputs and upload the object. for i, input := range putObjectInputs { // uploading the object. - _, err := obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, ObjectOptions{}) + _, err := obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -1393,7 +1393,7 @@ func testAPICopyObjectPartHandlerSanity(obj ObjectLayer, instanceType, bucketNam for i, input := range putObjectInputs { // uploading the object. _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, - mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, opts) + mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -1406,7 +1406,7 @@ func testAPICopyObjectPartHandlerSanity(obj ObjectLayer, instanceType, bucketNam // PutObjectPart API HTTP Handler has to be tested in isolation, // that is without any other handler being registered, // That's why NewMultipartUpload is initiated using ObjectLayer. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) @@ -1503,7 +1503,7 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri // iterate through the above set of inputs and upload the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, opts) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -1516,7 +1516,7 @@ func testAPICopyObjectPartHandler(obj ObjectLayer, instanceType, bucketName stri // PutObjectPart API HTTP Handler has to be tested in isolation, // that is without any other handler being registered, // That's why NewMultipartUpload is initiated using ObjectLayer. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) @@ -1863,7 +1863,7 @@ func testAPICopyObjectHandler(obj ObjectLayer, instanceType, bucketName string, for i, input := range putObjectInputs { // uploading the object. var objInfo ObjectInfo - objInfo, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, opts) + objInfo, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -2503,7 +2503,7 @@ func testAPICompleteMultipartHandler(obj ObjectLayer, instanceType, bucketName s for i := 0; i < 2; i++ { // initiate new multipart uploadID. - uploadID, err = obj.NewMultipartUpload(context.Background(), bucketName, objectName, nil, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucketName, objectName, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) @@ -2854,7 +2854,7 @@ func testAPIAbortMultipartHandler(obj ObjectLayer, instanceType, bucketName stri for i := 0; i < 2; i++ { // initiate new multipart uploadID. - uploadID, err = obj.NewMultipartUpload(context.Background(), bucketName, objectName, nil, opts) + uploadID, err = obj.NewMultipartUpload(context.Background(), bucketName, objectName, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) @@ -3006,7 +3006,6 @@ func testAPIDeleteObjectHandler(obj ObjectLayer, instanceType, bucketName string credentials auth.Credentials, t *testing.T) { var err error - var opts ObjectOptions objectName := "test-object" // Object used for anonymous API request test. anonObjectName := "test-anon-obj" @@ -3034,7 +3033,7 @@ func testAPIDeleteObjectHandler(obj ObjectLayer, instanceType, bucketName string // iterate through the above set of inputs and upload the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), input.metaData, opts) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData[""], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -3261,7 +3260,7 @@ func testAPIPutObjectPartHandler(obj ObjectLayer, instanceType, bucketName strin // PutObjectPart API HTTP Handler has to be tested in isolation, // that is without any other handler being registered, // That's why NewMultipartUpload is initiated using ObjectLayer. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) @@ -3664,7 +3663,7 @@ func testAPIListObjectPartsHandler(obj ObjectLayer, instanceType, bucketName str // PutObjectPart API HTTP Handler has to be tested in isolation, // that is without any other handler being registered, // That's why NewMultipartUpload is initiated using ObjectLayer. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, testObject, opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("Minio %s : %s", instanceType, err) diff --git a/cmd/object_api_suite_test.go b/cmd/object_api_suite_test.go index 648521a95..dd4383ae5 100644 --- a/cmd/object_api_suite_test.go +++ b/cmd/object_api_suite_test.go @@ -95,7 +95,7 @@ func testMultipartObjectCreation(obj ObjectLayer, instanceType string, t TestErr if err != nil { t.Fatalf("%s: %s", instanceType, err) } - uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -139,7 +139,7 @@ func testMultipartObjectAbort(obj ObjectLayer, instanceType string, t TestErrHan if err != nil { t.Fatalf("%s: %s", instanceType, err) } - uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), "bucket", "key", opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -180,8 +180,8 @@ func (s *ObjectLayerAPISuite) TestMultipleObjectCreation(t *testing.T) { // Tests validate object creation. func testMultipleObjectCreation(obj ObjectLayer, instanceType string, t TestErrHandler) { objects := make(map[string][]byte) - err := obj.MakeBucketWithLocation(context.Background(), "bucket", "") var opts ObjectOptions + err := obj.MakeBucketWithLocation(context.Background(), "bucket", "") if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -199,7 +199,7 @@ func testMultipleObjectCreation(obj ObjectLayer, instanceType string, t TestErrH metadata := make(map[string]string) metadata["etag"] = expectedETaghex var objInfo ObjectInfo - objInfo, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(randomString), int64(len(randomString)), metadata["etag"], ""), metadata, opts) + objInfo, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(randomString), int64(len(randomString)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -253,7 +253,7 @@ func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) { // check before paging occurs. for i := 0; i < 5; i++ { key := "obj" + strconv.Itoa(i) - _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -273,7 +273,7 @@ func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) { // check after paging occurs pages work. for i := 6; i <= 10; i++ { key := "obj" + strconv.Itoa(i) - _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", key, mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -290,11 +290,11 @@ func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) { } // check paging with prefix at end returns less objects. { - _, err = obj.PutObject(context.Background(), "bucket", "newPrefix", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "newPrefix", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } - _, err = obj.PutObject(context.Background(), "bucket", "newPrefix2", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "newPrefix2", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -332,11 +332,11 @@ func testPaging(obj ObjectLayer, instanceType string, t TestErrHandler) { // check delimited results with delimiter and prefix. { - _, err = obj.PutObject(context.Background(), "bucket", "this/is/delimited", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "this/is/delimited", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } - _, err = obj.PutObject(context.Background(), "bucket", "this/is/also/a/delimited/file", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "this/is/also/a/delimited/file", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -448,14 +448,14 @@ func testObjectOverwriteWorks(obj ObjectLayer, instanceType string, t TestErrHan var opts ObjectOptions uploadContent := "The list of parts was not in ascending order. The parts list must be specified in order by part number." length := int64(len(uploadContent)) - _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } uploadContent = "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." length = int64(len(uploadContent)) - _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -478,7 +478,7 @@ func (s *ObjectLayerAPISuite) TestNonExistantBucketOperations(t *testing.T) { // Tests validate that bucket operation on non-existent bucket fails. func testNonExistantBucketOperations(obj ObjectLayer, instanceType string, t TestErrHandler) { var opts ObjectOptions - _, err := obj.PutObject(context.Background(), "bucket1", "object", mustGetPutObjReader(t, bytes.NewBufferString("one"), int64(len("one")), "", ""), nil, opts) + _, err := obj.PutObject(context.Background(), "bucket1", "object", mustGetPutObjReader(t, bytes.NewBufferString("one"), int64(len("one")), "", ""), opts) if err == nil { t.Fatal("Expected error but found nil") } @@ -526,7 +526,7 @@ func testPutObject(obj ObjectLayer, instanceType string, t TestErrHandler) { var bytesBuffer1 bytes.Buffer var opts ObjectOptions - _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerEOF, length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerEOF, length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -539,7 +539,7 @@ func testPutObject(obj ObjectLayer, instanceType string, t TestErrHandler) { } var bytesBuffer2 bytes.Buffer - _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerNoEOF, length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "object", mustGetPutObjReader(t, readerNoEOF, length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -568,7 +568,7 @@ func testPutObjectInSubdir(obj ObjectLayer, instanceType string, t TestErrHandle uploadContent := `The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.` length := int64(len(uploadContent)) - _, err = obj.PutObject(context.Background(), "bucket", "dir1/dir2/object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "dir1/dir2/object", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } @@ -741,7 +741,7 @@ func testGetDirectoryReturnsObjectNotFound(obj ObjectLayer, instanceType string, content := "One or more of the specified parts could not be found. The part might not have been uploaded, or the specified entity tag might not have matched the part's entity tag." length := int64(len(content)) var opts ObjectOptions - _, err = obj.PutObject(context.Background(), bucketName, "dir1/dir3/object", mustGetPutObjReader(t, bytes.NewBufferString(content), length, "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucketName, "dir1/dir3/object", mustGetPutObjReader(t, bytes.NewBufferString(content), length, "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) @@ -783,7 +783,7 @@ func testContentType(obj ObjectLayer, instanceType string, t TestErrHandler) { var opts ObjectOptions uploadContent := "The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed." // Test empty. - _, err = obj.PutObject(context.Background(), "bucket", "minio.png", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), "bucket", "minio.png", mustGetPutObjReader(t, bytes.NewBufferString(uploadContent), int64(len(uploadContent)), "", ""), opts) if err != nil { t.Fatalf("%s: %s", instanceType, err) } diff --git a/cmd/storage-class_test.go b/cmd/storage-class_test.go index 2967b499b..b74e8ed74 100644 --- a/cmd/storage-class_test.go +++ b/cmd/storage-class_test.go @@ -189,7 +189,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin // Object for test case 1 - No StorageClass defined, no MetaData in PutObject object1 := "object1" - _, err = obj.PutObject(context.Background(), bucket, object1, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object1, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), opts) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -200,7 +200,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin object2 := "object2" metadata2 := make(map[string]string) metadata2["x-amz-storage-class"] = reducedRedundancyStorageClass - _, err = obj.PutObject(context.Background(), bucket, object2, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata2, opts) + _, err = obj.PutObject(context.Background(), bucket, object2, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata2}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -211,7 +211,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin object3 := "object3" metadata3 := make(map[string]string) metadata3["x-amz-storage-class"] = standardStorageClass - _, err = obj.PutObject(context.Background(), bucket, object3, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata3, opts) + _, err = obj.PutObject(context.Background(), bucket, object3, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata3}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -227,7 +227,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin Scheme: "EC", } - _, err = obj.PutObject(context.Background(), bucket, object4, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata4, opts) + _, err = obj.PutObject(context.Background(), bucket, object4, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata4}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -245,7 +245,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin Scheme: "EC", } - _, err = obj.PutObject(context.Background(), bucket, object5, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata5, opts) + _, err = obj.PutObject(context.Background(), bucket, object5, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata5}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -263,7 +263,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin Scheme: "EC", } - _, err = obj.PutObject(context.Background(), bucket, object6, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata6, opts) + _, err = obj.PutObject(context.Background(), bucket, object6, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata6}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -281,7 +281,7 @@ func testObjectQuorumFromMeta(obj ObjectLayer, instanceType string, dirs []strin Scheme: "EC", } - _, err = obj.PutObject(context.Background(), bucket, object7, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), metadata7, opts) + _, err = obj.PutObject(context.Background(), bucket, object7, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{UserDefined: metadata7}) if err != nil { t.Fatalf("Failed to putObject %v", err) } diff --git a/cmd/web-handlers.go b/cmd/web-handlers.go index a2927d300..02b122ad9 100644 --- a/cmd/web-handlers.go +++ b/cmd/web-handlers.go @@ -941,7 +941,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { pReader = NewPutObjReader(hashReader, nil, nil) // get gateway encryption options var opts ObjectOptions - opts, err = putEncryptionOpts(ctx, r, bucket, object, nil) + opts, err = putOpts(ctx, r, bucket, object, metadata) if err != nil { writeErrorResponseHeadersOnly(w, toAPIErrorCode(ctx, err)) return @@ -980,7 +980,7 @@ func (web *webAPIHandlers) Upload(w http.ResponseWriter, r *http.Request) { if !hasServerSideEncryptionHeader(r.Header) && web.CacheAPI() != nil { putObject = web.CacheAPI().PutObject } - objInfo, err := putObject(context.Background(), bucket, object, pReader, metadata, opts) + objInfo, err := putObject(context.Background(), bucket, object, pReader, opts) if err != nil { writeWebErrorResponse(w, err) return diff --git a/cmd/web-handlers_test.go b/cmd/web-handlers_test.go index 7bba46833..aa6ab1ba6 100644 --- a/cmd/web-handlers_test.go +++ b/cmd/web-handlers_test.go @@ -349,7 +349,7 @@ func testDeleteBucketWebHandler(obj ObjectLayer, instanceType string, t TestErrH for _, test := range testCases { if test.initWithObject { data := bytes.NewBufferString("hello") - _, err = obj.PutObject(context.Background(), test.bucketName, "object", mustGetPutObjReader(t, data, int64(data.Len()), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), test.bucketName, "object", mustGetPutObjReader(t, data, int64(data.Len()), "", ""), opts) // _, err = obj.PutObject(test.bucketName, "object", int64(data.Len()), data, nil, "") if err != nil { t.Fatalf("could not put object to %s, %s", test.bucketName, err.Error()) @@ -485,7 +485,7 @@ func testListObjectsWebHandler(obj ObjectLayer, instanceType string, t TestErrHa data := bytes.Repeat([]byte("a"), objectSize) metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"} - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), metadata, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("Was not able to upload an object, %v", err) @@ -589,14 +589,14 @@ func testRemoveObjectWebHandler(obj ObjectLayer, instanceType string, t TestErrH data := bytes.Repeat([]byte("a"), objectSize) metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"} - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), metadata, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("Was not able to upload an object, %v", err) } objectName = "a/object" metadata = map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"} - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), metadata, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("Was not able to upload an object, %v", err) } @@ -987,7 +987,7 @@ func testDownloadWebHandler(obj ObjectLayer, instanceType string, t TestErrHandl content := []byte("temporary file's content") metadata := map[string]string{"etag": "01ce59706106fe5e02e7f55fffda7f34"} - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(content), int64(len(content)), metadata["etag"], ""), metadata, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(content), int64(len(content)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("Was not able to upload an object, %v", err) } @@ -1090,9 +1090,9 @@ func testWebHandlerDownloadZip(obj ObjectLayer, instanceType string, t TestErrHa t.Fatalf("%s : %s", instanceType, err) } - obj.PutObject(context.Background(), bucket, "a/one", mustGetPutObjReader(t, strings.NewReader(fileOne), int64(len(fileOne)), "", ""), nil, opts) - obj.PutObject(context.Background(), bucket, "a/b/two", mustGetPutObjReader(t, strings.NewReader(fileTwo), int64(len(fileTwo)), "", ""), nil, opts) - obj.PutObject(context.Background(), bucket, "a/c/three", mustGetPutObjReader(t, strings.NewReader(fileThree), int64(len(fileThree)), "", ""), nil, opts) + obj.PutObject(context.Background(), bucket, "a/one", mustGetPutObjReader(t, strings.NewReader(fileOne), int64(len(fileOne)), "", ""), opts) + obj.PutObject(context.Background(), bucket, "a/b/two", mustGetPutObjReader(t, strings.NewReader(fileTwo), int64(len(fileTwo)), "", ""), opts) + obj.PutObject(context.Background(), bucket, "a/c/three", mustGetPutObjReader(t, strings.NewReader(fileThree), int64(len(fileThree)), "", ""), opts) test := func(token string) (int, []byte) { rec := httptest.NewRecorder() @@ -1177,7 +1177,7 @@ func testWebPresignedGetHandler(obj ObjectLayer, instanceType string, t TestErrH data := bytes.Repeat([]byte("a"), objectSize) metadata := map[string]string{"etag": "c9a34cfc85d982698c6ac89f76071abd"} - _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), metadata, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucketName, objectName, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), metadata["etag"], ""), ObjectOptions{UserDefined: metadata}) if err != nil { t.Fatalf("Was not able to upload an object, %v", err) } diff --git a/cmd/xl-sets.go b/cmd/xl-sets.go index 2f13bdfd9..6a1ee43c4 100644 --- a/cmd/xl-sets.go +++ b/cmd/xl-sets.go @@ -602,8 +602,8 @@ func (s *xlSets) GetObject(ctx context.Context, bucket, object string, startOffs } // PutObject - writes an object to hashedSet based on the object name. -func (s *xlSets) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { - return s.getHashedSet(object).PutObject(ctx, bucket, object, data, metadata, opts) +func (s *xlSets) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { + return s.getHashedSet(object).PutObject(ctx, bucket, object, data, opts) } // GetObjectInfo - reads object metadata from the hashedSet based on the object name. @@ -634,7 +634,8 @@ func (s *xlSets) CopyObject(ctx context.Context, srcBucket, srcObject, destBucke } defer objectDWLock.Unlock() } - return destSet.putObject(ctx, destBucket, destObject, srcInfo.PutObjReader, srcInfo.UserDefined, dstOpts) + putOpts := ObjectOptions{ServerSideEncryption: dstOpts.ServerSideEncryption, UserDefined: srcInfo.UserDefined} + return destSet.putObject(ctx, destBucket, destObject, srcInfo.PutObjReader, putOpts) } // Returns function "listDir" of the type listDirFunc. @@ -822,8 +823,8 @@ func (s *xlSets) ListMultipartUploads(ctx context.Context, bucket, prefix, keyMa } // Initiate a new multipart upload on a hashedSet based on object name. -func (s *xlSets) NewMultipartUpload(ctx context.Context, bucket, object string, metadata map[string]string, opts ObjectOptions) (uploadID string, err error) { - return s.getHashedSet(object).NewMultipartUpload(ctx, bucket, object, metadata, opts) +func (s *xlSets) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (uploadID string, err error) { + return s.getHashedSet(object).NewMultipartUpload(ctx, bucket, object, opts) } // Copies a part of an object from source hashedSet to destination hashedSet. diff --git a/cmd/xl-v1-common_test.go b/cmd/xl-v1-common_test.go index 96dadd028..fd063a952 100644 --- a/cmd/xl-v1-common_test.go +++ b/cmd/xl-v1-common_test.go @@ -43,7 +43,7 @@ func TestXLParentDirIsObject(t *testing.T) { } objectContent := "12345" objInfo, err := obj.PutObject(context.Background(), bucketName, objectName, - mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), nil, ObjectOptions{}) + mustGetPutObjReader(t, bytes.NewReader([]byte(objectContent)), int64(len(objectContent)), "", ""), ObjectOptions{}) if err != nil { t.Fatal(err) } diff --git a/cmd/xl-v1-healing-common_test.go b/cmd/xl-v1-healing-common_test.go index 160c3d43e..ae685a9d6 100644 --- a/cmd/xl-v1-healing-common_test.go +++ b/cmd/xl-v1-healing-common_test.go @@ -179,7 +179,7 @@ func TestListOnlineDisks(t *testing.T) { t.Fatalf("Failed to make a bucket %v", err) } - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{}) if err != nil { t.Fatalf("Failed to putObject %v", err) } @@ -273,7 +273,7 @@ func TestDisksWithAllParts(t *testing.T) { t.Fatalf("Failed to make a bucket %v", err) } - _, err = obj.PutObject(ctx, bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(ctx, bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), int64(len(data)), "", ""), ObjectOptions{}) if err != nil { t.Fatalf("Failed to putObject %v", err) } diff --git a/cmd/xl-v1-healing_test.go b/cmd/xl-v1-healing_test.go index fafedd75b..d1f7c6313 100644 --- a/cmd/xl-v1-healing_test.go +++ b/cmd/xl-v1-healing_test.go @@ -84,7 +84,7 @@ func TestHealObjectXL(t *testing.T) { // Create an object with multiple parts uploaded in decreasing // part number. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucket, object, opts) if err != nil { t.Fatalf("Failed to create a multipart upload - %v", err) } diff --git a/cmd/xl-v1-metadata_test.go b/cmd/xl-v1-metadata_test.go index 4d8200ae0..23dccea36 100644 --- a/cmd/xl-v1-metadata_test.go +++ b/cmd/xl-v1-metadata_test.go @@ -69,7 +69,7 @@ func testXLReadStat(obj ObjectLayer, instanceType string, disks []string, t *tes // iterate through the above set of inputs and upkoad the object. for i, input := range putObjectInputs { // uploading the object. - _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), input.metaData, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), input.bucketName, input.objectName, mustGetPutObjReader(t, bytes.NewBuffer(input.textData), input.contentLength, input.metaData["etag"], ""), ObjectOptions{UserDefined: input.metaData}) // if object upload fails stop the test. if err != nil { t.Fatalf("Put Object case %d: Error uploading object: %v", i+1, err) @@ -122,7 +122,7 @@ func testXLReadMetaParts(obj ObjectLayer, instanceType string, disks []string, t t.Fatalf("%s : %s", instanceType, err.Error()) } // Initiate Multipart Upload on the above created bucket. - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketNames[0], objectNames[0], opts) if err != nil { // Failed to create NewMultipartUpload, abort. t.Fatalf("%s : %s", instanceType, err.Error()) diff --git a/cmd/xl-v1-multipart.go b/cmd/xl-v1-multipart.go index 5117f3e38..20e0f3d37 100644 --- a/cmd/xl-v1-multipart.go +++ b/cmd/xl-v1-multipart.go @@ -241,15 +241,15 @@ func (xl xlObjects) newMultipartUpload(ctx context.Context, bucket string, objec // subsequent request each UUID is unique. // // Implements S3 compatible initiate multipart API. -func (xl xlObjects) NewMultipartUpload(ctx context.Context, bucket, object string, meta map[string]string, opts ObjectOptions) (string, error) { +func (xl xlObjects) NewMultipartUpload(ctx context.Context, bucket, object string, opts ObjectOptions) (string, error) { if err := checkNewMultipartArgs(ctx, bucket, object, xl); err != nil { return "", err } // No metadata is set, allocate a new one. - if meta == nil { - meta = make(map[string]string) + if opts.UserDefined == nil { + opts.UserDefined = make(map[string]string) } - return xl.newMultipartUpload(ctx, bucket, object, meta) + return xl.newMultipartUpload(ctx, bucket, object, opts.UserDefined) } // CopyObjectPart - reads incoming stream and internally erasure codes diff --git a/cmd/xl-v1-multipart_test.go b/cmd/xl-v1-multipart_test.go index 1f749405b..e51dda004 100644 --- a/cmd/xl-v1-multipart_test.go +++ b/cmd/xl-v1-multipart_test.go @@ -43,7 +43,7 @@ func TestXLCleanupStaleMultipartUploads(t *testing.T) { var opts ObjectOptions obj.MakeBucketWithLocation(context.Background(), bucketName, "") - uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, objectName, nil, opts) + uploadID, err := obj.NewMultipartUpload(context.Background(), bucketName, objectName, opts) if err != nil { t.Fatal("Unexpected err: ", err) } diff --git a/cmd/xl-v1-object.go b/cmd/xl-v1-object.go index f4d6c3a52..0a4050312 100644 --- a/cmd/xl-v1-object.go +++ b/cmd/xl-v1-object.go @@ -131,8 +131,8 @@ func (xl xlObjects) CopyObject(ctx context.Context, srcBucket, srcObject, dstBuc logger.LogIf(ctx, err) return oi, toObjectErr(err, dstBucket, dstObject) } - - objInfo, err := xl.putObject(ctx, dstBucket, dstObject, NewPutObjReader(hashReader, nil, nil), srcInfo.UserDefined, dstOpts) + putOpts := ObjectOptions{UserDefined: srcInfo.UserDefined, ServerSideEncryption: dstOpts.ServerSideEncryption} + objInfo, err := xl.putObject(ctx, dstBucket, dstObject, NewPutObjReader(hashReader, nil, nil), putOpts) if err != nil { return oi, toObjectErr(err, dstBucket, dstObject) } @@ -531,7 +531,7 @@ func rename(ctx context.Context, disks []StorageAPI, srcBucket, srcEntry, dstBuc // until EOF, erasure codes the data across all disk and additionally // writes `xl.json` which carries the necessary metadata for future // object operations. -func (xl xlObjects) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { +func (xl xlObjects) PutObject(ctx context.Context, bucket string, object string, data *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { // Validate put object input args. if err = checkPutObjectArgs(ctx, bucket, object, xl, data.Size()); err != nil { return ObjectInfo{}, err @@ -543,22 +543,22 @@ func (xl xlObjects) PutObject(ctx context.Context, bucket string, object string, return objInfo, err } defer objectLock.Unlock() - return xl.putObject(ctx, bucket, object, data, metadata, opts) + return xl.putObject(ctx, bucket, object, data, opts) } // putObject wrapper for xl PutObject -func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, r *PutObjReader, metadata map[string]string, opts ObjectOptions) (objInfo ObjectInfo, err error) { +func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, r *PutObjReader, opts ObjectOptions) (objInfo ObjectInfo, err error) { data := r.Reader uniqueID := mustGetUUID() tempObj := uniqueID // No metadata is set, allocate a new one. - if metadata == nil { - metadata = make(map[string]string) + if opts.UserDefined == nil { + opts.UserDefined = make(map[string]string) } // Get parity and data drive count based on storage class metadata - dataDrives, parityDrives := getRedundancyCount(metadata[amzStorageClass], len(xl.getDisks())) + dataDrives, parityDrives := getRedundancyCount(opts.UserDefined[amzStorageClass], len(xl.getDisks())) // we now know the number of blocks this object needs for data and parity. // writeQuorum is dataBlocks + 1 @@ -590,7 +590,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, return ObjectInfo{}, toObjectErr(err, bucket, object) } - return dirObjectInfo(bucket, object, data.Size(), metadata), nil + return dirObjectInfo(bucket, object, data.Size(), opts.UserDefined), nil } // Validate put object input args. @@ -733,11 +733,11 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, // Save additional erasureMetadata. modTime := UTCNow() - metadata["etag"] = r.MD5CurrentHexString() + opts.UserDefined["etag"] = r.MD5CurrentHexString() // Guess content-type from the extension if possible. - if metadata["content-type"] == "" { - metadata["content-type"] = mimedb.TypeByExtension(path.Ext(object)) + if opts.UserDefined["content-type"] == "" { + opts.UserDefined["content-type"] = mimedb.TypeByExtension(path.Ext(object)) } if xl.isObject(bucket, object) { @@ -764,7 +764,7 @@ func (xl xlObjects) putObject(ctx context.Context, bucket string, object string, // Fill all the necessary metadata. // Update `xl.json` content on each disks. for index := range partsMetadata { - partsMetadata[index].Meta = metadata + partsMetadata[index].Meta = opts.UserDefined partsMetadata[index].Stat.Size = sizeWritten partsMetadata[index].Stat.ModTime = modTime } diff --git a/cmd/xl-v1-object_test.go b/cmd/xl-v1-object_test.go index 889a0e448..329cfd516 100644 --- a/cmd/xl-v1-object_test.go +++ b/cmd/xl-v1-object_test.go @@ -49,7 +49,7 @@ func TestRepeatPutObjectPart(t *testing.T) { t.Fatal(err) } - uploadID, err := objLayer.NewMultipartUpload(context.Background(), "bucket1", "mpartObj1", nil, opts) + uploadID, err := objLayer.NewMultipartUpload(context.Background(), "bucket1", "mpartObj1", opts) if err != nil { t.Fatal(err) } @@ -94,7 +94,7 @@ func TestXLDeleteObjectBasic(t *testing.T) { } // Create object "dir/obj" under bucket "bucket" for Test 7 to pass - _, err = xl.PutObject(context.Background(), "bucket", "dir/obj", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, ObjectOptions{}) + _, err = xl.PutObject(context.Background(), "bucket", "dir/obj", mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), ObjectOptions{}) if err != nil { t.Fatalf("XL Object upload failed: %s", err) } @@ -131,7 +131,7 @@ func TestXLDeleteObjectDiskNotFound(t *testing.T) { object := "object" opts := ObjectOptions{} // Create object "obj" under bucket "bucket". - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), opts) if err != nil { t.Fatal(err) } @@ -146,7 +146,7 @@ func TestXLDeleteObjectDiskNotFound(t *testing.T) { } // Create "obj" under "bucket". - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), opts) if err != nil { t.Fatal(err) } @@ -182,7 +182,7 @@ func TestGetObjectNoQuorum(t *testing.T) { object := "object" opts := ObjectOptions{} // Create "object" under "bucket". - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), opts) if err != nil { t.Fatal(err) } @@ -233,7 +233,7 @@ func TestPutObjectNoQuorum(t *testing.T) { object := "object" opts := ObjectOptions{} // Create "object" under "bucket". - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), opts) if err != nil { t.Fatal(err) } @@ -256,7 +256,7 @@ func TestPutObjectNoQuorum(t *testing.T) { } } // Upload new content to same object "object" - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), nil, opts) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader([]byte("abcd")), int64(len("abcd")), "", ""), opts) if err != toObjectErr(errXLWriteQuorum, bucket, object) { t.Errorf("Expected putObject to fail with %v, but failed with %v", toObjectErr(errXLWriteQuorum, bucket, object), err) } @@ -290,7 +290,7 @@ func TestHealing(t *testing.T) { t.Fatal(err) } - _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), length, "", ""), nil, ObjectOptions{}) + _, err = obj.PutObject(context.Background(), bucket, object, mustGetPutObjReader(t, bytes.NewReader(data), length, "", ""), ObjectOptions{}) if err != nil { t.Fatal(err) }