From 9fdb69563d1ca77585f0af570128a55499a107c3 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Thu, 19 May 2016 17:10:08 -0700 Subject: [PATCH] handler: CopyObject should save metadata. (#1698) - Content-Type - Content-Encoding - ETag Fixes #1682 --- bucket-handlers.go | 7 ++++++- object-common-multipart.go | 4 ++++ object-datatypes.go | 15 ++++++++------- object-handlers.go | 10 +++++++++- server_xl_test.go | 4 +++- xl-objects-multipart.go | 12 +++++++----- xl-objects.go | 19 ++++++++++++++----- 7 files changed, 51 insertions(+), 20 deletions(-) diff --git a/bucket-handlers.go b/bucket-handlers.go index a0ec8cd78..645136401 100644 --- a/bucket-handlers.go +++ b/bucket-handlers.go @@ -492,7 +492,12 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h writeErrorResponse(w, r, apiErr, r.URL.Path) return } - md5Sum, err := api.ObjectAPI.PutObject(bucket, object, -1, fileBody, nil) + + // Save metadata. + metadata := make(map[string]string) + // Nothing to store right now. + + md5Sum, err := api.ObjectAPI.PutObject(bucket, object, -1, fileBody, metadata) if err != nil { errorIf(err, "Unable to create object.") writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path) diff --git a/object-common-multipart.go b/object-common-multipart.go index c64b27e09..10cde6b68 100644 --- a/object-common-multipart.go +++ b/object-common-multipart.go @@ -85,6 +85,10 @@ func newMultipartUploadCommon(storage StorageAPI, bucket string, object string, if !IsValidObjectName(object) { return "", ObjectNameInvalid{Bucket: bucket, Object: object} } + // No metadata is set, allocate a new one. + if meta == nil { + meta = make(map[string]string) + } // This lock needs to be held for any changes to the directory contents of ".minio/multipart/object/" nsMutex.Lock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object)) defer nsMutex.Unlock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object)) diff --git a/object-datatypes.go b/object-datatypes.go index 274d4e83c..a893dfd8d 100644 --- a/object-datatypes.go +++ b/object-datatypes.go @@ -28,13 +28,14 @@ type BucketInfo struct { // ObjectInfo - object info. type ObjectInfo struct { - Bucket string - Name string - ModTime time.Time - ContentType string - MD5Sum string - Size int64 - IsDir bool + Bucket string + Name string + ModTime time.Time + Size int64 + IsDir bool + MD5Sum string + ContentType string + ContentEncoding string } // ListPartsInfo - various types of object resources. diff --git a/object-handlers.go b/object-handlers.go index d3d4a65d6..c82bbf6fb 100644 --- a/object-handlers.go +++ b/object-handlers.go @@ -404,8 +404,16 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re // Size of object. size := objInfo.Size + // Save metadata. + metadata := make(map[string]string) + // Save other metadata if available. + metadata["content-type"] = objInfo.ContentType + metadata["content-encoding"] = objInfo.ContentEncoding + // Do not set `md5sum` as CopyObject will not keep the + // same md5sum as the source. + // Create the object. - md5Sum, err := api.ObjectAPI.PutObject(bucket, object, size, readCloser, nil) + md5Sum, err := api.ObjectAPI.PutObject(bucket, object, size, readCloser, metadata) if err != nil { errorIf(err, "Unable to create an object.") writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path) diff --git a/server_xl_test.go b/server_xl_test.go index 6872813d6..a27c9f4ae 100644 --- a/server_xl_test.go +++ b/server_xl_test.go @@ -624,6 +624,7 @@ func (s *MyAPIXLSuite) TestPutBucket(c *C) { } +// Tests copy object. func (s *MyAPIXLSuite) TestCopyObject(c *C) { request, err := s.newRequest("PUT", testAPIXLServer.URL+"/put-object-copy", 0, nil) c.Assert(err, IsNil) @@ -635,6 +636,7 @@ func (s *MyAPIXLSuite) TestCopyObject(c *C) { buffer1 := bytes.NewReader([]byte("hello world")) request, err = s.newRequest("PUT", testAPIXLServer.URL+"/put-object-copy/object", int64(buffer1.Len()), buffer1) + request.Header.Set("Content-Type", "application/json") c.Assert(err, IsNil) response, err = client.Do(request) @@ -657,8 +659,8 @@ func (s *MyAPIXLSuite) TestCopyObject(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) object, err := ioutil.ReadAll(response.Body) c.Assert(err, IsNil) - c.Assert(string(object), Equals, "hello world") + c.Assert(response.Header.Get("Content-Type"), Equals, "application/json") } func (s *MyAPIXLSuite) TestPutObject(c *C) { diff --git a/xl-objects-multipart.go b/xl-objects-multipart.go index 4274384ee..01d0780db 100644 --- a/xl-objects-multipart.go +++ b/xl-objects-multipart.go @@ -37,11 +37,12 @@ type MultipartPartInfo struct { // MultipartObjectInfo - contents of the multipart metadata file after // CompleteMultipartUpload() is called. type MultipartObjectInfo struct { - Parts []MultipartPartInfo - ModTime time.Time - Size int64 - MD5Sum string - ContentType string + Parts []MultipartPartInfo + ModTime time.Time + Size int64 + MD5Sum string + ContentType string + ContentEncoding string // Add more fields here. } @@ -212,6 +213,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload // Save successfully calculated md5sum. metadata.MD5Sum = s3MD5 metadata.ContentType = objMeta["content-type"] + metadata.ContentEncoding = objMeta["content-encoding"] // Save modTime as well as the current time. metadata.ModTime = time.Now().UTC() diff --git a/xl-objects.go b/xl-objects.go index cba4855da..3f812cd32 100644 --- a/xl-objects.go +++ b/xl-objects.go @@ -250,6 +250,7 @@ func (xl xlObjects) getObjectInfo(bucket, object string) (objInfo ObjectInfo, er objInfo.ModTime = info.ModTime objInfo.MD5Sum = info.MD5Sum objInfo.ContentType = info.ContentType + objInfo.ContentEncoding = info.ContentEncoding } else { metadata := make(map[string]string) offset := int64(0) // To read entire content @@ -276,6 +277,7 @@ func (xl xlObjects) getObjectInfo(bucket, object string) (objInfo ObjectInfo, er objInfo.ModTime = fi.ModTime objInfo.MD5Sum = metadata["md5Sum"] objInfo.ContentType = contentType + objInfo.ContentEncoding = metadata["content-encoding"] } return objInfo, nil } @@ -315,6 +317,10 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. Object: object, } } + // No metadata is set, allocate a new one. + if metadata == nil { + metadata = make(map[string]string) + } nsMutex.Lock(bucket, object) defer nsMutex.Unlock(bucket, object) @@ -348,11 +354,13 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. } newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil)) - // md5Hex representation. - var md5Hex string - if len(metadata) != 0 { - md5Hex = metadata["md5Sum"] + // Update the md5sum if not set with the newly calculated one. + if len(metadata["md5Sum"]) == 0 { + metadata["md5Sum"] = newMD5Hex } + + // md5Hex representation. + md5Hex := metadata["md5Sum"] if md5Hex != "" { if newMD5Hex != md5Hex { if err = safeCloseAndRemove(fileWriter); err != nil { @@ -361,6 +369,7 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. return "", BadDigest{md5Hex, newMD5Hex} } } + err = fileWriter.Close() if err != nil { if clErr := safeCloseAndRemove(fileWriter); clErr != nil { @@ -369,7 +378,7 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io. return "", toObjectErr(err, bucket, object) } - // check if an object is present as one of the parent dir. + // Check if an object is present as one of the parent dir. if err = xl.parentDirIsObject(bucket, path.Dir(object)); err != nil { return "", toObjectErr(err, bucket, object) }