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
master
Anis Elleuch 8 years ago committed by Harshavardhana
parent 45d9cfa0c5
commit 70e70446bb
  1. 32
      cmd/object-handlers_test.go
  2. 11
      cmd/streaming-signature-v4.go

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

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

Loading…
Cancel
Save