mirror of https://github.com/minio/minio.git
multipart: reject part upload if size is less than 5MB. (#1518)
This commit is contained in:
parent
88e1c04259
commit
75320f70d0
|
@ -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)
|
||||||
|
|
7
utils.go
7
utils.go
|
@ -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…
Reference in New Issue