diff --git a/cmd/storage-rpc-client.go b/cmd/storage-rpc-client.go index 15d881605..149069f7d 100644 --- a/cmd/storage-rpc-client.go +++ b/cmd/storage-rpc-client.go @@ -49,6 +49,9 @@ func splitNetPath(networkPath string) (netAddr, netPath string) { // written so that the storageAPI errors are consistent across network // disks as well. func toStorageErr(err error) error { + if err == nil { + return nil + } switch err.Error() { case io.EOF.Error(): return io.EOF @@ -240,16 +243,18 @@ func (n networkStorage) ReadFile(volume string, path string, offset int64, buffe if n.rpcClient == nil { return 0, errVolumeBusy } - if err = n.rpcClient.Call("Storage.ReadFileHandler", ReadFileArgs{ + var result []byte + err = n.rpcClient.Call("Storage.ReadFileHandler", ReadFileArgs{ Token: n.rpcToken, Vol: volume, Path: path, Offset: offset, - Buffer: buffer, - }, &m); err != nil { - return 0, toStorageErr(err) - } - return m, nil + Size: len(buffer), + }, &result) + // Copy results to buffer. + copy(buffer, result) + // Return length of result, err if any. + return int64(len(result)), toStorageErr(err) } // ListDir - list all entries at prefix. diff --git a/cmd/storage-rpc-server-datatypes.go b/cmd/storage-rpc-server-datatypes.go index ec33935ff..7cd908a32 100644 --- a/cmd/storage-rpc-server-datatypes.go +++ b/cmd/storage-rpc-server-datatypes.go @@ -76,8 +76,8 @@ type ReadFileArgs struct { // Starting offset to start reading into Buffer. Offset int64 - // Data buffer read from the path at offset. - Buffer []byte + // Data size read from the path at offset. + Size int } // AppendFileArgs represents append file RPC arguments. diff --git a/cmd/storage-rpc-server.go b/cmd/storage-rpc-server.go index adbd0172c..6da801545 100644 --- a/cmd/storage-rpc-server.go +++ b/cmd/storage-rpc-server.go @@ -17,8 +17,10 @@ package main import ( + "bytes" "errors" "fmt" + "io" "net/rpc" "path" "strings" @@ -162,16 +164,29 @@ func (s *storageServer) ReadAllHandler(args *ReadFileArgs, reply *[]byte) error } // ReadFileHandler - read file handler is rpc wrapper to read file. -func (s *storageServer) ReadFileHandler(args *ReadFileArgs, reply *int64) error { +func (s *storageServer) ReadFileHandler(args *ReadFileArgs, reply *[]byte) (err error) { + defer func() { + if r := recover(); r != nil { + // Recover any panic and return ErrCacheFull. + err = bytes.ErrTooLarge + } + }() // Do not crash the server. if !isRPCTokenValid(args.Token) { return errors.New("Invalid token") } - n, err := s.storage.ReadFile(args.Vol, args.Path, args.Offset, args.Buffer) - if err != nil { - return err + // Allocate the requested buffer from the client. + *reply = make([]byte, args.Size) + var n int64 + n, err = s.storage.ReadFile(args.Vol, args.Path, args.Offset, *reply) + // Sending an error over the rpc layer, would cause unmarshalling to fail. In situations + // when we have short read i.e `io.ErrUnexpectedEOF` treat it as good condition and copy + // the buffer properly. + if err == io.ErrUnexpectedEOF { + // Reset to nil as good condition. + err = nil } - *reply = n - return nil + *reply = (*reply)[0:n] + return err } // AppendFileHandler - append file handler is rpc wrapper to append file.