signv4: Read always returns EOF when stream ends (#3692)

When EOF is reached, further calls of Read() doesn't return io.EOF
but continue to work as it expects to have more data, this PR fixes
the behavior
This commit is contained in:
Anis Elleuch 2017-02-06 23:19:27 +01:00 committed by Harshavardhana
parent 45d9cfa0c5
commit 70e70446bb
2 changed files with 32 additions and 11 deletions

View File

@ -489,6 +489,20 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: true, shouldPass: true,
}, },
// Test case - 3 // Test case - 3
// Empty data
{
bucketName: bucketName,
objectName: objectName,
data: []byte{},
dataLen: 0,
chunkSize: 64 * humanize.KiByte,
expectedContent: []byte{},
expectedRespStatus: http.StatusOK,
accessKey: credentials.AccessKey,
secretKey: credentials.SecretKey,
shouldPass: true,
},
// Test case - 4
// Invalid access key id. // Invalid access key id.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -502,7 +516,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
secretKey: "", secretKey: "",
shouldPass: false, shouldPass: false,
}, },
// Test case - 4 // Test case - 5
// Wrong auth header returns as bad request. // Wrong auth header returns as bad request.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -517,7 +531,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: false, shouldPass: false,
removeAuthHeader: true, removeAuthHeader: true,
}, },
// Test case - 5 // Test case - 6
// Large chunk size.. also passes. // Large chunk size.. also passes.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -531,7 +545,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
secretKey: credentials.SecretKey, secretKey: credentials.SecretKey,
shouldPass: false, shouldPass: false,
}, },
// Test case - 6 // Test case - 7
// Chunk with malformed encoding. // Chunk with malformed encoding.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -546,7 +560,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: false, shouldPass: false,
fault: malformedEncoding, fault: malformedEncoding,
}, },
// Test case - 7 // Test case - 8
// Chunk with shorter than advertised chunk data. // Chunk with shorter than advertised chunk data.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -561,7 +575,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: false, shouldPass: false,
fault: unexpectedEOF, fault: unexpectedEOF,
}, },
// Test case - 8 // Test case - 9
// Chunk with first chunk data byte tampered. // Chunk with first chunk data byte tampered.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -576,7 +590,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: false, shouldPass: false,
fault: signatureMismatch, fault: signatureMismatch,
}, },
// Test case - 9 // Test case - 10
// Different date (timestamps) used in seed signature calculation // Different date (timestamps) used in seed signature calculation
// and chunks signature calculation. // and chunks signature calculation.
{ {
@ -592,7 +606,7 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
shouldPass: false, shouldPass: false,
fault: chunkDateMismatch, fault: chunkDateMismatch,
}, },
// Test case - 10 // Test case - 11
// Set x-amz-decoded-content-length to a value too big to hold in int64. // Set x-amz-decoded-content-length to a value too big to hold in int64.
{ {
bucketName: bucketName, bucketName: bucketName,
@ -669,11 +683,11 @@ func testAPIPutObjectStreamSigV4Handler(obj ObjectLayer, instanceType, bucketNam
} }
buffer := new(bytes.Buffer) buffer := new(bytes.Buffer)
err = obj.GetObject(testCase.bucketName, testCase.objectName, 0, int64(bytesDataLen), buffer) err = obj.GetObject(testCase.bucketName, testCase.objectName, 0, int64(testCase.dataLen), buffer)
if err != nil { if err != nil {
t.Fatalf("Test %d: %s: Failed to fetch the copied object: <ERROR> %s", i+1, instanceType, err) t.Fatalf("Test %d: %s: Failed to fetch the copied object: <ERROR> %s", i+1, instanceType, err)
} }
if !bytes.Equal(bytesData, buffer.Bytes()) { if !bytes.Equal(testCase.data, buffer.Bytes()) {
t.Errorf("Test %d: %s: Data Mismatch: Data fetched back from the uploaded object doesn't match the original one.", i+1, instanceType) t.Errorf("Test %d: %s: Data Mismatch: Data fetched back from the uploaded object doesn't match the original one.", i+1, instanceType)
} }
buffer.Reset() buffer.Reset()

View File

@ -221,6 +221,7 @@ const (
readChunkTrailer readChunkTrailer
readChunk readChunk
verifyChunk verifyChunk
eofChunk
) )
func (cs chunkState) String() string { func (cs chunkState) String() string {
@ -234,6 +235,9 @@ func (cs chunkState) String() string {
stateString = "readChunk" stateString = "readChunk"
case verifyChunk: case verifyChunk:
stateString = "verifyChunk" stateString = "verifyChunk"
case eofChunk:
stateString = "eofChunk"
} }
return stateString return stateString
} }
@ -309,10 +313,13 @@ func (cr *s3ChunkedReader) Read(buf []byte) (n int, err error) {
// this follows the chaining. // this follows the chaining.
cr.seedSignature = newSignature cr.seedSignature = newSignature
cr.chunkSHA256Writer.Reset() cr.chunkSHA256Writer.Reset()
cr.state = readChunkHeader
if cr.lastChunk { if cr.lastChunk {
return n, nil cr.state = eofChunk
} else {
cr.state = readChunkHeader
} }
case eofChunk:
return n, io.EOF
} }
} }
} }