From 967c2b29409f447645f55dbc7fd20077ae07ae36 Mon Sep 17 00:00:00 2001 From: Krishnan Parthasarathi Date: Mon, 30 May 2016 23:57:15 +0530 Subject: [PATCH] Handled possible short writes to httpResponseWriter (#1804) * XL: Handled possible short writes to httpResponseWriter * Added tests for Range Header combinations --- erasure-readfile.go | 4 ++-- server_xl_test.go | 31 ++++++++++++++++++++----------- xl-v1-object.go | 15 ++++++++------- 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/erasure-readfile.go b/erasure-readfile.go index 5edaab574..02d9eac0b 100644 --- a/erasure-readfile.go +++ b/erasure-readfile.go @@ -19,7 +19,7 @@ package main import "errors" // ReadFile - decoded erasure coded file. -func (e erasure) ReadFile(volume, path string, bufferOffset int64, startOffset int64, buffer []byte) (int64, error) { +func (e erasure) ReadFile(volume, path string, startOffset int64, buffer []byte) (int64, error) { // Calculate the current encoded block size. curEncBlockSize := getEncodedBlockLen(int64(len(buffer)), e.DataBlocks) offsetEncOffset := getEncodedBlockLen(startOffset, e.DataBlocks) @@ -89,7 +89,7 @@ func (e erasure) ReadFile(volume, path string, bufferOffset int64, startOffset i } // Copy data blocks. - copy(buffer, dataBlocks[bufferOffset:]) + copy(buffer, dataBlocks) // Relenquish memory. dataBlocks = nil diff --git a/server_xl_test.go b/server_xl_test.go index c6eff8e3d..69cf96d75 100644 --- a/server_xl_test.go +++ b/server_xl_test.go @@ -920,18 +920,27 @@ func (s *MyAPIXLSuite) TestPartialContent(c *C) { c.Assert(response.StatusCode, Equals, http.StatusOK) // Prepare request - request, err = s.newRequest("GET", testAPIXLServer.URL+"/partial-content/bar", 0, nil) - c.Assert(err, IsNil) - request.Header.Add("Range", "bytes=6-7") + var table = []struct { + byteRange string + expectedString string + }{ + {"6-7", "Wo"}, + {"6-", "World"}, + {"-7", "o World"}, + } + for _, t := range table { + request, err = s.newRequest("GET", testAPIXLServer.URL+"/partial-content/bar", 0, nil) + c.Assert(err, IsNil) + request.Header.Add("Range", "bytes="+t.byteRange) - client = http.Client{} - response, err = client.Do(request) - c.Assert(err, IsNil) - c.Assert(response.StatusCode, Equals, http.StatusPartialContent) - partialObject, err := ioutil.ReadAll(response.Body) - c.Assert(err, IsNil) - - c.Assert(string(partialObject), Equals, "Wo") + client = http.Client{} + response, err = client.Do(request) + c.Assert(err, IsNil) + c.Assert(response.StatusCode, Equals, http.StatusPartialContent) + partialObject, err := ioutil.ReadAll(response.Body) + c.Assert(err, IsNil) + c.Assert(string(partialObject), Equals, t.expectedString) + } } func (s *MyAPIXLSuite) TestListObjectsHandlerErrors(c *C) { diff --git a/xl-v1-object.go b/xl-v1-object.go index a0a6abd33..3fc9ef889 100644 --- a/xl-v1-object.go +++ b/xl-v1-object.go @@ -1,6 +1,7 @@ package main import ( + "bytes" "crypto/md5" "encoding/hex" "io" @@ -63,27 +64,27 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i } var buffer = make([]byte, curBlockSize) var n int64 - n, err = erasure.ReadFile(bucket, pathJoin(object, part.Name), partOffset, beginOffset, buffer) + n, err = erasure.ReadFile(bucket, pathJoin(object, part.Name), beginOffset, buffer) if err != nil { return err } if length > int64(len(buffer)) { - var m int - m, err = writer.Write(buffer) + var m int64 + m, err = io.Copy(writer, bytes.NewReader(buffer[partOffset:])) if err != nil { return err } - length -= int64(m) + length -= m } else { - _, err = writer.Write(buffer[:length]) + _, err = io.CopyN(writer, bytes.NewReader(buffer[partOffset:]), length) if err != nil { return err } return nil } - totalLeft -= partOffset + n + totalLeft -= n beginOffset += n - // Reset part offset to 0 to read rest of the parts from the beginning. + // Reset part offset to 0 to read rest of the part from the beginning. partOffset = 0 } }