1
mirror of https://github.com/rclone/rclone synced 2024-12-22 13:03:02 +01:00

fs: Adjust RangeOption.Decode to return -1 for read to end

A Range request can never request 0 bytes however this change was made
to make a clearer signal that the limit means read to the end.

Add test and more documentation and fixup uses
This commit is contained in:
Nick Craig-Wood 2018-01-27 10:07:17 +00:00
parent 9a73688e3a
commit fe52502f19
7 changed files with 42 additions and 14 deletions

View File

@ -220,11 +220,11 @@ func (o *Object) Open(options ...fs.OpenOption) (io.ReadCloser, error) {
var err error var err error
cacheReader := NewObjectHandle(o) cacheReader := NewObjectHandle(o)
var offset, limit int64 var offset, limit int64 = 0, -1
for _, option := range options { for _, option := range options {
switch x := option.(type) { switch x := option.(type) {
case *fs.SeekOption: case *fs.SeekOption:
offset, limit = x.Offset, 0 offset = x.Offset
case *fs.RangeOption: case *fs.RangeOption:
offset, limit = x.Decode(o.Size()) offset, limit = x.Decode(o.Size())
} }

View File

@ -634,11 +634,11 @@ func (f *ftpReadCloser) Close() error {
func (o *Object) Open(options ...fs.OpenOption) (rc io.ReadCloser, err error) { func (o *Object) Open(options ...fs.OpenOption) (rc io.ReadCloser, err error) {
// defer fs.Trace(o, "")("rc=%v, err=%v", &rc, &err) // defer fs.Trace(o, "")("rc=%v, err=%v", &rc, &err)
path := path.Join(o.fs.root, o.remote) path := path.Join(o.fs.root, o.remote)
var offset, limit int64 var offset, limit int64 = 0, -1
for _, option := range options { for _, option := range options {
switch x := option.(type) { switch x := option.(type) {
case *fs.SeekOption: case *fs.SeekOption:
offset, limit = x.Offset, 0 offset = x.Offset
case *fs.RangeOption: case *fs.RangeOption:
offset, limit = x.Decode(o.Size()) offset, limit = x.Decode(o.Size())
default: default:

View File

@ -676,13 +676,12 @@ func (file *localOpenFile) Close() (err error) {
// Open an object for read // Open an object for read
func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) { func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
var offset int64 var offset, limit int64 = 0, -1
var limit int64
hashes := hash.Supported hashes := hash.Supported
for _, option := range options { for _, option := range options {
switch x := option.(type) { switch x := option.(type) {
case *fs.SeekOption: case *fs.SeekOption:
offset, limit = x.Offset, 0 offset = x.Offset
case *fs.RangeOption: case *fs.RangeOption:
offset, limit = x.Decode(o.size) offset, limit = x.Decode(o.size)
case *fs.HashesOption: case *fs.HashesOption:

View File

@ -855,11 +855,11 @@ func (file *ObjectReader) Close() (err error) {
// Open a remote sftp file object for reading. Seek is supported // Open a remote sftp file object for reading. Seek is supported
func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) { func (o *Object) Open(options ...fs.OpenOption) (in io.ReadCloser, err error) {
var offset, limit int64 var offset, limit int64 = 0, -1
for _, option := range options { for _, option := range options {
switch x := option.(type) { switch x := option.(type) {
case *fs.SeekOption: case *fs.SeekOption:
offset, limit = x.Offset, 0 offset = x.Offset
case *fs.RangeOption: case *fs.RangeOption:
offset, limit = x.Decode(o.Size()) offset, limit = x.Decode(o.Size())
default: default:

View File

@ -97,17 +97,25 @@ func (o *RangeOption) Mandatory() bool {
} }
// Decode interprets the RangeOption into an offset and a limit // Decode interprets the RangeOption into an offset and a limit
//
// The offset is the start of the stream and the limit is how many
// bytes should be read from it. If the limit is -1 then the stream
// should be read to the end.
func (o *RangeOption) Decode(size int64) (offset, limit int64) { func (o *RangeOption) Decode(size int64) (offset, limit int64) {
if o.Start >= 0 { if o.Start >= 0 {
offset = o.Start offset = o.Start
if o.End >= 0 { if o.End >= 0 {
limit = o.End - o.Start + 1 limit = o.End - o.Start + 1
} else { } else {
limit = 0 limit = -1
} }
} else { } else {
offset = size - o.End if o.End >= 0 {
limit = 0 offset = size - o.End
} else {
offset = 0
}
limit = -1
} }
return offset, limit return offset, limit
} }

View File

@ -37,3 +37,24 @@ func TestParseRangeOption(t *testing.T) {
} }
} }
} }
func TestRangeOptionDecode(t *testing.T) {
for _, test := range []struct {
in RangeOption
size int64
wantOffset int64
wantLimit int64
}{
{in: RangeOption{Start: 1, End: 10}, size: 100, wantOffset: 1, wantLimit: 10},
{in: RangeOption{Start: 10, End: 10}, size: 100, wantOffset: 10, wantLimit: 1},
{in: RangeOption{Start: 10, End: 9}, size: 100, wantOffset: 10, wantLimit: 0},
{in: RangeOption{Start: 1, End: -1}, size: 100, wantOffset: 1, wantLimit: -1},
{in: RangeOption{Start: -1, End: 90}, size: 100, wantOffset: 10, wantLimit: -1},
{in: RangeOption{Start: -1, End: -1}, size: 100, wantOffset: 0, wantLimit: -1},
} {
gotOffset, gotLimit := test.in.Decode(test.size)
what := fmt.Sprintf("%+v size=%d", test.in, test.size)
assert.Equal(t, test.wantOffset, gotOffset, "offset "+what)
assert.Equal(t, test.wantLimit, gotLimit, "limit "+what)
}
}

View File

@ -9,10 +9,10 @@ type LimitedReadCloser struct {
} }
// NewLimitedReadCloser returns a LimitedReadCloser wrapping rc to // NewLimitedReadCloser returns a LimitedReadCloser wrapping rc to
// limit it to reading limit bytes. If limit == 0 then it does not // limit it to reading limit bytes. If limit < 0 then it does not
// wrap rc, it just returns it. // wrap rc, it just returns it.
func NewLimitedReadCloser(rc io.ReadCloser, limit int64) (lrc io.ReadCloser) { func NewLimitedReadCloser(rc io.ReadCloser, limit int64) (lrc io.ReadCloser) {
if limit == 0 { if limit < 0 {
return rc return rc
} }
return &LimitedReadCloser{ return &LimitedReadCloser{