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:
Krishna Srinivas 2016-10-22 21:35:01 +05:30 committed by Harshavardhana
parent e51be73ac7
commit 5999a23d3e
6 changed files with 65 additions and 1 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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