Handled possible short writes to httpResponseWriter (#1804)

* XL: Handled possible short writes to httpResponseWriter

* Added tests for Range Header combinations
master
Krishnan Parthasarathi 9 years ago committed by Harshavardhana
parent b466f27705
commit 967c2b2940
  1. 4
      erasure-readfile.go
  2. 33
      server_xl_test.go
  3. 15
      xl-v1-object.go

@ -19,7 +19,7 @@ package main
import "errors" import "errors"
// ReadFile - decoded erasure coded file. // 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. // Calculate the current encoded block size.
curEncBlockSize := getEncodedBlockLen(int64(len(buffer)), e.DataBlocks) curEncBlockSize := getEncodedBlockLen(int64(len(buffer)), e.DataBlocks)
offsetEncOffset := getEncodedBlockLen(startOffset, 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 data blocks.
copy(buffer, dataBlocks[bufferOffset:]) copy(buffer, dataBlocks)
// Relenquish memory. // Relenquish memory.
dataBlocks = nil dataBlocks = nil

@ -920,18 +920,27 @@ func (s *MyAPIXLSuite) TestPartialContent(c *C) {
c.Assert(response.StatusCode, Equals, http.StatusOK) c.Assert(response.StatusCode, Equals, http.StatusOK)
// Prepare request // Prepare request
request, err = s.newRequest("GET", testAPIXLServer.URL+"/partial-content/bar", 0, nil) var table = []struct {
c.Assert(err, IsNil) byteRange string
request.Header.Add("Range", "bytes=6-7") expectedString string
}{
client = http.Client{} {"6-7", "Wo"},
response, err = client.Do(request) {"6-", "World"},
c.Assert(err, IsNil) {"-7", "o World"},
c.Assert(response.StatusCode, Equals, http.StatusPartialContent) }
partialObject, err := ioutil.ReadAll(response.Body) for _, t := range table {
c.Assert(err, IsNil) request, err = s.newRequest("GET", testAPIXLServer.URL+"/partial-content/bar", 0, nil)
c.Assert(err, IsNil)
c.Assert(string(partialObject), Equals, "Wo") 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, t.expectedString)
}
} }
func (s *MyAPIXLSuite) TestListObjectsHandlerErrors(c *C) { func (s *MyAPIXLSuite) TestListObjectsHandlerErrors(c *C) {

@ -1,6 +1,7 @@
package main package main
import ( import (
"bytes"
"crypto/md5" "crypto/md5"
"encoding/hex" "encoding/hex"
"io" "io"
@ -63,27 +64,27 @@ func (xl xlObjects) GetObject(bucket, object string, startOffset int64, length i
} }
var buffer = make([]byte, curBlockSize) var buffer = make([]byte, curBlockSize)
var n int64 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 { if err != nil {
return err return err
} }
if length > int64(len(buffer)) { if length > int64(len(buffer)) {
var m int var m int64
m, err = writer.Write(buffer) m, err = io.Copy(writer, bytes.NewReader(buffer[partOffset:]))
if err != nil { if err != nil {
return err return err
} }
length -= int64(m) length -= m
} else { } else {
_, err = writer.Write(buffer[:length]) _, err = io.CopyN(writer, bytes.NewReader(buffer[partOffset:]), length)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
totalLeft -= partOffset + n totalLeft -= n
beginOffset += 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 partOffset = 0
} }
} }

Loading…
Cancel
Save