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

master
Krishna Srinivas 9 years ago committed by Harshavardhana
parent 88e1c04259
commit 75320f70d0
  1. 2
      api-errors.go
  2. 16
      object-errors.go
  3. 9
      object_api_suite_test.go
  4. 9
      server_xl_test.go
  5. 7
      utils.go
  6. 3
      xl-objects-multipart.go

@ -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
} }

@ -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"
}

@ -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.

@ -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)

@ -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 {

@ -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,

Loading…
Cancel
Save