From 04a5b259296a8739534a7c75669bd449e2849c28 Mon Sep 17 00:00:00 2001 From: Krishna Srinivas Date: Mon, 9 May 2016 12:19:49 +0530 Subject: [PATCH] Multipart: Minimum part size limit does not apply to the last part during CompleteMultipartUpload. (#1518) (#1538) --- fs-objects-multipart.go | 14 +++++++++++++- server_test.go | 16 +++++++++++++--- server_xl_test.go | 7 +++++++ xl-objects-multipart.go | 5 +++-- 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/fs-objects-multipart.go b/fs-objects-multipart.go index 0c042c84b..fe0df802b 100644 --- a/fs-objects-multipart.go +++ b/fs-objects-multipart.go @@ -73,10 +73,22 @@ func (fs fsObjects) CompleteMultipartUpload(bucket string, object string, upload } // Loop through all parts, validate them and then commit to disk. - for _, part := range parts { + for i, part := range parts { // Construct part suffix. partSuffix := fmt.Sprintf("%.5d.%s", part.PartNumber, part.ETag) multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix) + var fi FileInfo + fi, err = fs.storage.StatFile(minioMetaBucket, multipartPartFile) + if err != nil { + if err == errFileNotFound { + return "", InvalidPart{} + } + return "", err + } + // All parts except the last part has to be atleast 5MB. + if (i < len(parts)-1) && !isMinAllowedPartSize(fi.Size) { + return "", PartTooSmall{} + } var fileReader io.ReadCloser fileReader, err = fs.storage.ReadFile(minioMetaBucket, multipartPartFile, 0) if err != nil { diff --git a/server_test.go b/server_test.go index b43b8dff5..d7e30de3e 100644 --- a/server_test.go +++ b/server_test.go @@ -1244,11 +1244,14 @@ func (s *MyAPISuite) TestObjectMultipart(c *C) { c.Assert(len(newResponse.UploadID) > 0, Equals, true) uploadID := newResponse.UploadID + // Create a byte array of 5MB. + data := bytes.Repeat([]byte("0123456789abcdef"), 5*1024*1024/16) + hasher := md5.New() - hasher.Write([]byte("hello world")) + hasher.Write(data) md5Sum := hasher.Sum(nil) - buffer1 := bytes.NewReader([]byte("hello world")) + buffer1 := bytes.NewReader(data) request, err = s.newRequest("PUT", testAPIFSCacheServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", int64(buffer1.Len()), buffer1) request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) c.Assert(err, IsNil) @@ -1258,7 +1261,14 @@ func (s *MyAPISuite) TestObjectMultipart(c *C) { c.Assert(err, IsNil) c.Assert(response1.StatusCode, Equals, http.StatusOK) - buffer2 := bytes.NewReader([]byte("hello world")) + // Byte array one 1 byte. + data = []byte("0") + + hasher = md5.New() + hasher.Write(data) + md5Sum = hasher.Sum(nil) + + buffer2 := bytes.NewReader(data) request, err = s.newRequest("PUT", testAPIFSCacheServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", int64(buffer2.Len()), buffer2) request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) c.Assert(err, IsNil) diff --git a/server_xl_test.go b/server_xl_test.go index d852a03de..cbe07bc3d 100644 --- a/server_xl_test.go +++ b/server_xl_test.go @@ -1279,6 +1279,13 @@ func (s *MyAPIXLSuite) TestObjectMultipart(c *C) { c.Assert(err, IsNil) c.Assert(response1.StatusCode, Equals, http.StatusOK) + // Create a byte array of 1 byte. + data = []byte("0") + + hasher = md5.New() + hasher.Write(data) + md5Sum = hasher.Sum(nil) + buffer2 := bytes.NewReader(data) request, err = s.newRequest("PUT", testAPIXLServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", int64(buffer2.Len()), buffer2) request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) diff --git a/xl-objects-multipart.go b/xl-objects-multipart.go index b3f8ea81c..9fa356334 100644 --- a/xl-objects-multipart.go +++ b/xl-objects-multipart.go @@ -124,7 +124,7 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload var wg = &sync.WaitGroup{} // Loop through all parts, validate them and then commit to disk. - for _, part := range parts { + for i, part := range parts { // Construct part suffix. partSuffix := fmt.Sprintf("%.5d.%s", part.PartNumber, part.ETag) multipartPartFile := path.Join(mpartMetaPrefix, bucket, object, uploadID, partSuffix) @@ -136,7 +136,8 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload } return "", err } - if !isMinAllowedPartSize(fi.Size) { + // All parts except the last part has to be atleast 5MB. + if (i < len(parts)-1) && !isMinAllowedPartSize(fi.Size) { return "", PartTooSmall{} } // Update metadata parts.