mirror of
https://github.com/minio/minio.git
synced 2024-12-24 22:25:54 -05:00
When object whose size is greater than 5G is uploaded using presigned POST we should return error. (#3033)
fixes #2961
This commit is contained in:
parent
e51be73ac7
commit
5999a23d3e
@ -627,6 +627,8 @@ func toAPIErrorCode(err error) (apiErr APIErrorCode) {
|
|||||||
apiErr = ErrEntityTooSmall
|
apiErr = ErrEntityTooSmall
|
||||||
case SHA256Mismatch:
|
case SHA256Mismatch:
|
||||||
apiErr = ErrContentSHA256Mismatch
|
apiErr = ErrContentSHA256Mismatch
|
||||||
|
case ObjectTooLarge:
|
||||||
|
apiErr = ErrEntityTooLarge
|
||||||
default:
|
default:
|
||||||
apiErr = ErrInternalError
|
apiErr = ErrInternalError
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@ func extractPostPolicyFormValues(reader *multipart.Reader) (filePart io.Reader,
|
|||||||
}
|
}
|
||||||
formValues[canonicalFormName] = string(buffer)
|
formValues[canonicalFormName] = string(buffer)
|
||||||
} else {
|
} else {
|
||||||
filePart = io.LimitReader(part, maxObjectSize)
|
filePart = limitReader(part, maxObjectSize)
|
||||||
fileName = part.FileName()
|
fileName = part.FileName()
|
||||||
// As described in S3 spec, we expect file to be the last form field
|
// As described in S3 spec, we expect file to be the last form field
|
||||||
break
|
break
|
||||||
|
@ -74,6 +74,13 @@ func toObjectErr(err error, params ...string) error {
|
|||||||
Object: params[1],
|
Object: params[1],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case errDataTooLarge:
|
||||||
|
if len(params) >= 2 {
|
||||||
|
err = ObjectTooLarge{
|
||||||
|
Bucket: params[0],
|
||||||
|
Object: params[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
case errXLReadQuorum:
|
case errXLReadQuorum:
|
||||||
err = InsufficientReadQuorum{}
|
err = InsufficientReadQuorum{}
|
||||||
case errXLWriteQuorum:
|
case errXLWriteQuorum:
|
||||||
@ -252,6 +259,13 @@ func (e InvalidRange) Error() string {
|
|||||||
return fmt.Sprintf("The requested range \"bytes %d-%d/%d\" is not satisfiable.", e.offsetBegin, e.offsetEnd, e.resourceSize)
|
return fmt.Sprintf("The requested range \"bytes %d-%d/%d\" is not satisfiable.", e.offsetBegin, e.offsetEnd, e.resourceSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ObjectTooLarge error returned when the size of the object > max object size allowed (5G) per request.
|
||||||
|
type ObjectTooLarge GenericError
|
||||||
|
|
||||||
|
func (e ObjectTooLarge) Error() string {
|
||||||
|
return "size of the object greater than what is allowed(5G)"
|
||||||
|
}
|
||||||
|
|
||||||
/// Multipart related errors.
|
/// Multipart related errors.
|
||||||
|
|
||||||
// MalformedUploadID malformed upload id.
|
// MalformedUploadID malformed upload id.
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@ -161,3 +162,24 @@ type byBucketName []BucketInfo
|
|||||||
func (d byBucketName) Len() int { return len(d) }
|
func (d byBucketName) Len() int { return len(d) }
|
||||||
func (d byBucketName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
func (d byBucketName) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
|
||||||
func (d byBucketName) Less(i, j int) bool { return d[i].Name < d[j].Name }
|
func (d byBucketName) Less(i, j int) bool { return d[i].Name < d[j].Name }
|
||||||
|
|
||||||
|
// Copied from io.LimitReader()
|
||||||
|
// limitReader returns a Reader that reads from r
|
||||||
|
// but returns error after n bytes.
|
||||||
|
// The underlying implementation is a *LimitedReader.
|
||||||
|
type limitedReader struct {
|
||||||
|
R io.Reader // underlying reader
|
||||||
|
N int64 // max bytes remaining
|
||||||
|
}
|
||||||
|
|
||||||
|
func limitReader(r io.Reader, n int64) io.Reader { return &limitedReader{r, n} }
|
||||||
|
|
||||||
|
func (l *limitedReader) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = l.R.Read(p)
|
||||||
|
l.N -= int64(n)
|
||||||
|
if l.N < 0 {
|
||||||
|
// If more data is available than what is expected we return error.
|
||||||
|
return 0, errDataTooLarge
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -113,3 +115,24 @@ func TestIsValidObjectName(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tests limitReader
|
||||||
|
func TestLimitReader(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
data string
|
||||||
|
maxLen int64
|
||||||
|
err error
|
||||||
|
}{
|
||||||
|
{"1234567890", 15, nil},
|
||||||
|
{"1234567890", 10, nil},
|
||||||
|
{"1234567890", 5, errDataTooLarge},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, test := range testCases {
|
||||||
|
r := strings.NewReader(test.data)
|
||||||
|
_, err := ioutil.ReadAll(limitReader(r, test.maxLen))
|
||||||
|
if err != test.err {
|
||||||
|
t.Fatalf("test %d failed: expected %v, got %v", i+1, test.err, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -35,3 +35,6 @@ var errContentSHA256Mismatch = errors.New("Content checksum SHA256 mismatch")
|
|||||||
|
|
||||||
// used when we deal with data larger than expected
|
// used when we deal with data larger than expected
|
||||||
var errSizeUnexpected = errors.New("Data size larger than expected")
|
var errSizeUnexpected = errors.New("Data size larger than expected")
|
||||||
|
|
||||||
|
// When upload object size is greater than 5G in a single PUT/POST operation.
|
||||||
|
var errDataTooLarge = errors.New("Object size larger than allowed limit")
|
||||||
|
Loading…
Reference in New Issue
Block a user