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:
parent
9a73688e3a
commit
fe52502f19
4
backend/cache/object.go
vendored
4
backend/cache/object.go
vendored
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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{
|
||||||
|
Loading…
Reference in New Issue
Block a user