imagekit: fix Open with a RangeOption returning the wrong data
Open decoded range options against an unknown size, producing a negative offset for suffix ranges (eg the last N bytes) and sending syntactically invalid Range headers which the server ignored. A suffix range then returned the whole file instead of the requested tail. Decode the options against the known object size so the offset is always absolute, only send a Range header when one was requested, and honour the requested count when the server ignores the Range header.
This commit is contained in:
@@ -593,12 +593,12 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
var offset int64
|
||||
var count int64
|
||||
|
||||
fs.FixRangeOption(options, -1)
|
||||
fs.FixRangeOption(options, o.Size())
|
||||
partialContent := false
|
||||
for _, option := range options {
|
||||
switch x := option.(type) {
|
||||
case *fs.RangeOption:
|
||||
offset, count = x.Decode(-1)
|
||||
offset, count = x.Decode(o.Size())
|
||||
partialContent = true
|
||||
case *fs.SeekOption:
|
||||
offset = x.Offset
|
||||
@@ -626,7 +626,13 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
|
||||
client := &http.Client{}
|
||||
req, _ := http.NewRequest("GET", url, nil)
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+count-1))
|
||||
if partialContent {
|
||||
if count > 0 {
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", offset, offset+count-1))
|
||||
} else {
|
||||
req.Header.Set("Range", fmt.Sprintf("bytes=%d-", offset))
|
||||
}
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
|
||||
if err != nil {
|
||||
@@ -636,13 +642,9 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
end := resp.ContentLength
|
||||
|
||||
if partialContent && resp.StatusCode == http.StatusOK {
|
||||
skip := offset
|
||||
|
||||
if offset < 0 {
|
||||
skip = end + offset + 1
|
||||
}
|
||||
|
||||
_, err = io.CopyN(io.Discard, resp.Body, skip)
|
||||
// The server ignored the Range request so skip to the
|
||||
// offset and limit what is read ourselves
|
||||
_, err = io.CopyN(io.Discard, resp.Body, offset)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
_ = resp.Body.Close()
|
||||
@@ -650,7 +652,11 @@ func (o *Object) Open(ctx context.Context, options ...fs.OpenOption) (io.ReadClo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return readers.NewLimitedReadCloser(resp.Body, end-skip), nil
|
||||
limit := end - offset
|
||||
if count > 0 && count < limit {
|
||||
limit = count
|
||||
}
|
||||
return readers.NewLimitedReadCloser(resp.Body, limit), nil
|
||||
}
|
||||
|
||||
return resp.Body, nil
|
||||
|
||||
Reference in New Issue
Block a user