multipart: reject part upload if size is less than 5MB. (#1518)

This commit is contained in:
Krishna Srinivas 2016-05-09 00:36:05 +05:30 committed by Harshavardhana
parent 88e1c04259
commit 75320f70d0
6 changed files with 39 additions and 7 deletions

View File

@ -458,6 +458,8 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) {
apiErr = ErrWriteQuorum apiErr = ErrWriteQuorum
case InsufficientReadQuorum: case InsufficientReadQuorum:
apiErr = ErrReadQuorum apiErr = ErrReadQuorum
case PartTooSmall:
apiErr = ErrEntityTooSmall
default: default:
apiErr = ErrInternalError apiErr = ErrInternalError
} }

View File

@ -233,3 +233,19 @@ type InvalidPart struct{}
func (e InvalidPart) Error() string { func (e InvalidPart) Error() string {
return "One or more of the specified parts could not be found" return "One or more of the specified parts could not be found"
} }
// InvalidPartOrder parts are not ordered as Requested
type InvalidPartOrder struct {
UploadID string
}
func (e InvalidPartOrder) Error() string {
return "Invalid part order sent for " + e.UploadID
}
// PartTooSmall - error if part size is less than 5MB.
type PartTooSmall struct{}
func (e PartTooSmall) Error() string {
return "Part size should be atleast 5MB"
}

View File

@ -63,22 +63,23 @@ func testMultipartObjectCreation(c *check.C, create func() ObjectLayer) {
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
uploadID, err := obj.NewMultipartUpload("bucket", "key") uploadID, err := obj.NewMultipartUpload("bucket", "key")
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
// Create a byte array of 5MB.
data := bytes.Repeat([]byte("0123456789abcdef"), 5*1024*1024/16)
completedParts := completeMultipartUpload{} completedParts := completeMultipartUpload{}
for i := 1; i <= 10; i++ { for i := 1; i <= 10; i++ {
hasher := md5.New() hasher := md5.New()
hasher.Write([]byte("The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.")) hasher.Write(data)
expectedMD5Sumhex := hex.EncodeToString(hasher.Sum(nil)) expectedMD5Sumhex := hex.EncodeToString(hasher.Sum(nil))
var calculatedMD5sum string var calculatedMD5sum string
calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len("The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed.")), bytes.NewBufferString("The specified multipart upload does not exist. The upload ID might be invalid, or the multipart upload might have been aborted or completed."), expectedMD5Sumhex) calculatedMD5sum, err = obj.PutObjectPart("bucket", "key", uploadID, i, int64(len(data)), bytes.NewBuffer(data), expectedMD5Sumhex)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
c.Assert(calculatedMD5sum, check.Equals, expectedMD5Sumhex) c.Assert(calculatedMD5sum, check.Equals, expectedMD5Sumhex)
completedParts.Parts = append(completedParts.Parts, completePart{PartNumber: i, ETag: calculatedMD5sum}) completedParts.Parts = append(completedParts.Parts, completePart{PartNumber: i, ETag: calculatedMD5sum})
} }
md5Sum, err := obj.CompleteMultipartUpload("bucket", "key", uploadID, completedParts.Parts) md5Sum, err := obj.CompleteMultipartUpload("bucket", "key", uploadID, completedParts.Parts)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
c.Assert(md5Sum, check.Equals, "7dd76eded6f7c3580a78463a7cf539bd-10") c.Assert(md5Sum, check.Equals, "7d364cb728ce42a74a96d22949beefb2-10")
} }
// Tests validate abortion of Multipart operation. // Tests validate abortion of Multipart operation.

View File

@ -1262,11 +1262,14 @@ func (s *MyAPIXLSuite) TestObjectMultipart(c *C) {
c.Assert(len(newResponse.UploadID) > 0, Equals, true) c.Assert(len(newResponse.UploadID) > 0, Equals, true)
uploadID := newResponse.UploadID uploadID := newResponse.UploadID
// Create a byte array of 5MB.
data := bytes.Repeat([]byte("0123456789abcdef"), 5*1024*1024/16)
hasher := md5.New() hasher := md5.New()
hasher.Write([]byte("hello world")) hasher.Write(data)
md5Sum := hasher.Sum(nil) md5Sum := hasher.Sum(nil)
buffer1 := bytes.NewReader([]byte("hello world")) buffer1 := bytes.NewReader(data)
request, err = s.newRequest("PUT", testAPIXLServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", int64(buffer1.Len()), buffer1) request, err = s.newRequest("PUT", testAPIXLServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=1", int64(buffer1.Len()), buffer1)
request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum)) request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum))
c.Assert(err, IsNil) c.Assert(err, IsNil)
@ -1276,7 +1279,7 @@ func (s *MyAPIXLSuite) TestObjectMultipart(c *C) {
c.Assert(err, IsNil) c.Assert(err, IsNil)
c.Assert(response1.StatusCode, Equals, http.StatusOK) c.Assert(response1.StatusCode, Equals, http.StatusOK)
buffer2 := bytes.NewReader([]byte("hello world")) buffer2 := bytes.NewReader(data)
request, err = s.newRequest("PUT", testAPIXLServer.URL+"/objectmultiparts/object?uploadId="+uploadID+"&partNumber=2", int64(buffer2.Len()), buffer2) 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)) request.Header.Set("Content-Md5", base64.StdEncoding.EncodeToString(md5Sum))
c.Assert(err, IsNil) c.Assert(err, IsNil)

View File

@ -38,6 +38,8 @@ func checkValidMD5(md5 string) ([]byte, error) {
const ( const (
// maximum object size per PUT request is 5GiB // maximum object size per PUT request is 5GiB
maxObjectSize = 1024 * 1024 * 1024 * 5 maxObjectSize = 1024 * 1024 * 1024 * 5
// minimum Part size for multipart upload is 5MB
minPartSize = 1024 * 1024 * 5
) )
// isMaxObjectSize - verify if max object size // isMaxObjectSize - verify if max object size
@ -45,6 +47,11 @@ func isMaxObjectSize(size int64) bool {
return size > maxObjectSize return size > maxObjectSize
} }
// Check if part size is more than or equal to minimum allowed size.
func isMinAllowedPartSize(size int64) bool {
return size >= minPartSize
}
func contains(stringList []string, element string) bool { func contains(stringList []string, element string) bool {
for _, e := range stringList { for _, e := range stringList {
if e == element { if e == element {

View File

@ -136,6 +136,9 @@ func (xl xlObjects) CompleteMultipartUpload(bucket string, object string, upload
} }
return "", err return "", err
} }
if !isMinAllowedPartSize(fi.Size) {
return "", PartTooSmall{}
}
// Update metadata parts. // Update metadata parts.
metadata.Parts = append(metadata.Parts, MultipartPartInfo{ metadata.Parts = append(metadata.Parts, MultipartPartInfo{
PartNumber: part.PartNumber, PartNumber: part.PartNumber,