handler: CopyObject should save metadata. (#1698)

- Content-Type
- Content-Encoding
- ETag

Fixes #1682
master
Harshavardhana 9 years ago committed by Anand Babu (AB) Periasamy
parent 00d0558131
commit 9fdb69563d
  1. 7
      bucket-handlers.go
  2. 4
      object-common-multipart.go
  3. 15
      object-datatypes.go
  4. 10
      object-handlers.go
  5. 4
      server_xl_test.go
  6. 12
      xl-objects-multipart.go
  7. 19
      xl-objects.go

@ -492,7 +492,12 @@ func (api objectAPIHandlers) PostPolicyBucketHandler(w http.ResponseWriter, r *h
writeErrorResponse(w, r, apiErr, r.URL.Path) writeErrorResponse(w, r, apiErr, r.URL.Path)
return 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 { if err != nil {
errorIf(err, "Unable to create object.") errorIf(err, "Unable to create object.")
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path) writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)

@ -85,6 +85,10 @@ func newMultipartUploadCommon(storage StorageAPI, bucket string, object string,
if !IsValidObjectName(object) { if !IsValidObjectName(object) {
return "", ObjectNameInvalid{Bucket: bucket, Object: 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/" // This lock needs to be held for any changes to the directory contents of ".minio/multipart/object/"
nsMutex.Lock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object)) nsMutex.Lock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object))
defer nsMutex.Unlock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object)) defer nsMutex.Unlock(minioMetaBucket, pathJoin(mpartMetaPrefix, bucket, object))

@ -28,13 +28,14 @@ type BucketInfo struct {
// ObjectInfo - object info. // ObjectInfo - object info.
type ObjectInfo struct { type ObjectInfo struct {
Bucket string Bucket string
Name string Name string
ModTime time.Time ModTime time.Time
ContentType string Size int64
MD5Sum string IsDir bool
Size int64 MD5Sum string
IsDir bool ContentType string
ContentEncoding string
} }
// ListPartsInfo - various types of object resources. // ListPartsInfo - various types of object resources.

@ -404,8 +404,16 @@ func (api objectAPIHandlers) CopyObjectHandler(w http.ResponseWriter, r *http.Re
// Size of object. // Size of object.
size := objInfo.Size 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. // 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 { if err != nil {
errorIf(err, "Unable to create an object.") errorIf(err, "Unable to create an object.")
writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path) writeErrorResponse(w, r, toAPIErrorCode(err), r.URL.Path)

@ -624,6 +624,7 @@ func (s *MyAPIXLSuite) TestPutBucket(c *C) {
} }
// Tests copy object.
func (s *MyAPIXLSuite) TestCopyObject(c *C) { func (s *MyAPIXLSuite) TestCopyObject(c *C) {
request, err := s.newRequest("PUT", testAPIXLServer.URL+"/put-object-copy", 0, nil) request, err := s.newRequest("PUT", testAPIXLServer.URL+"/put-object-copy", 0, nil)
c.Assert(err, IsNil) c.Assert(err, IsNil)
@ -635,6 +636,7 @@ func (s *MyAPIXLSuite) TestCopyObject(c *C) {
buffer1 := bytes.NewReader([]byte("hello world")) buffer1 := bytes.NewReader([]byte("hello world"))
request, err = s.newRequest("PUT", testAPIXLServer.URL+"/put-object-copy/object", int64(buffer1.Len()), buffer1) 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) c.Assert(err, IsNil)
response, err = client.Do(request) response, err = client.Do(request)
@ -657,8 +659,8 @@ func (s *MyAPIXLSuite) TestCopyObject(c *C) {
c.Assert(response.StatusCode, Equals, http.StatusOK) c.Assert(response.StatusCode, Equals, http.StatusOK)
object, err := ioutil.ReadAll(response.Body) object, err := ioutil.ReadAll(response.Body)
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(string(object), Equals, "hello world") c.Assert(string(object), Equals, "hello world")
c.Assert(response.Header.Get("Content-Type"), Equals, "application/json")
} }
func (s *MyAPIXLSuite) TestPutObject(c *C) { func (s *MyAPIXLSuite) TestPutObject(c *C) {

@ -37,11 +37,12 @@ type MultipartPartInfo struct {
// MultipartObjectInfo - contents of the multipart metadata file after // MultipartObjectInfo - contents of the multipart metadata file after
// CompleteMultipartUpload() is called. // CompleteMultipartUpload() is called.
type MultipartObjectInfo struct { type MultipartObjectInfo struct {
Parts []MultipartPartInfo Parts []MultipartPartInfo
ModTime time.Time ModTime time.Time
Size int64 Size int64
MD5Sum string MD5Sum string
ContentType string ContentType string
ContentEncoding string
// Add more fields here. // Add more fields here.
} }
@ -212,6 +213,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload
// Save successfully calculated md5sum. // Save successfully calculated md5sum.
metadata.MD5Sum = s3MD5 metadata.MD5Sum = s3MD5
metadata.ContentType = objMeta["content-type"] metadata.ContentType = objMeta["content-type"]
metadata.ContentEncoding = objMeta["content-encoding"]
// Save modTime as well as the current time. // Save modTime as well as the current time.
metadata.ModTime = time.Now().UTC() metadata.ModTime = time.Now().UTC()

@ -250,6 +250,7 @@ func (xl xlObjects) getObjectInfo(bucket, object string) (objInfo ObjectInfo, er
objInfo.ModTime = info.ModTime objInfo.ModTime = info.ModTime
objInfo.MD5Sum = info.MD5Sum objInfo.MD5Sum = info.MD5Sum
objInfo.ContentType = info.ContentType objInfo.ContentType = info.ContentType
objInfo.ContentEncoding = info.ContentEncoding
} else { } else {
metadata := make(map[string]string) metadata := make(map[string]string)
offset := int64(0) // To read entire content 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.ModTime = fi.ModTime
objInfo.MD5Sum = metadata["md5Sum"] objInfo.MD5Sum = metadata["md5Sum"]
objInfo.ContentType = contentType objInfo.ContentType = contentType
objInfo.ContentEncoding = metadata["content-encoding"]
} }
return objInfo, nil return objInfo, nil
} }
@ -315,6 +317,10 @@ func (xl xlObjects) PutObject(bucket string, object string, size int64, data io.
Object: object, Object: object,
} }
} }
// No metadata is set, allocate a new one.
if metadata == nil {
metadata = make(map[string]string)
}
nsMutex.Lock(bucket, object) nsMutex.Lock(bucket, object)
defer nsMutex.Unlock(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)) newMD5Hex := hex.EncodeToString(md5Writer.Sum(nil))
// md5Hex representation. // Update the md5sum if not set with the newly calculated one.
var md5Hex string if len(metadata["md5Sum"]) == 0 {
if len(metadata) != 0 { metadata["md5Sum"] = newMD5Hex
md5Hex = metadata["md5Sum"]
} }
// md5Hex representation.
md5Hex := metadata["md5Sum"]
if md5Hex != "" { if md5Hex != "" {
if newMD5Hex != md5Hex { if newMD5Hex != md5Hex {
if err = safeCloseAndRemove(fileWriter); err != nil { 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} return "", BadDigest{md5Hex, newMD5Hex}
} }
} }
err = fileWriter.Close() err = fileWriter.Close()
if err != nil { if err != nil {
if clErr := safeCloseAndRemove(fileWriter); clErr != 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) 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 { if err = xl.parentDirIsObject(bucket, path.Dir(object)); err != nil {
return "", toObjectErr(err, bucket, object) return "", toObjectErr(err, bucket, object)
} }

Loading…
Cancel
Save