change http range func

This commit is contained in:
divyam234 2023-12-04 14:58:28 +05:30
parent 1e2da6d627
commit 0a1c5d679e
2 changed files with 38 additions and 77 deletions

View file

@ -2,105 +2,66 @@ package http_range
import (
"errors"
"fmt"
"net/textproto"
"strconv"
"strings"
)
// Range specifies the byte range to be sent to the client.
type Range struct {
Start int64
End int64
}
// ContentRange returns Content-Range header value.
func (r Range) ContentRange(size int64) string {
return fmt.Sprintf("bytes %d-%d/%d", r.Start, r.End, size)
}
var (
// ErrNoOverlap is returned by ParseRange if first-byte-pos of
// all of the byte-range-spec values is greater than the content size.
ErrNoOverlap = errors.New("invalid range: failed to overlap")
// ErrInvalid is returned by ParseRange on invalid input.
ErrInvalid = errors.New("invalid range")
)
// ParseRange parses a Range header string as per RFC 7233.
// ErrNoOverlap is returned if none of the ranges overlap.
// ErrInvalid is returned if s is invalid range.
func ParseRange(s string, size int64) ([]Range, error) { // nolint:gocognit
if s == "" {
return nil, nil // header not present
}
const b = "bytes="
if !strings.HasPrefix(s, b) {
func Parse(header string, size int64) ([]*Range, error) {
index := strings.Index(header, "=")
if index == -1 {
return nil, ErrInvalid
}
var ranges []Range
noOverlap := false
for _, ra := range strings.Split(s[len(b):], ",") {
ra = textproto.TrimString(ra)
if ra == "" {
size64 := int64(size)
arr := strings.Split(header[index+1:], ",")
ranges := make([]*Range, 0, len(arr))
for _, value := range arr {
r := strings.Split(value, "-")
start, startErr := strconv.ParseInt(r[0], 10, 64)
end, endErr := strconv.ParseInt(r[1], 10, 64)
if startErr != nil && endErr != nil {
continue
}
i := strings.Index(ra, "-")
if i < 0 {
return nil, ErrInvalid
// -nnn and nnn-
if startErr != nil {
start = size64 - end
end = size64 - 1
} else if endErr != nil {
end = size64 - 1
}
start, end := textproto.TrimString(ra[:i]), textproto.TrimString(ra[i+1:])
var r Range
if start == "" {
// If no start is specified, end specifies the
// range start relative to the end of the file,
// and we are dealing with <suffix-length>
// which has to be a non-negative integer as per
// RFC 7233 Section 2.1 "Byte-Ranges".
if end == "" || end[0] == '-' {
return nil, ErrInvalid
if end >= size64 {
end = size64 - 1
}
i, err := strconv.ParseInt(end, 10, 64)
if i < 0 || err != nil {
return nil, ErrInvalid
}
if i > size {
i = size
}
r.Start = size - i
r.End = size - 1
} else {
i, err := strconv.ParseInt(start, 10, 64)
if err != nil || i < 0 {
return nil, ErrInvalid
}
if i >= size {
// If the range begins after the size of the content,
// then it does not overlap.
noOverlap = true
if start > end || start < 0 {
continue
}
r.Start = i
if end == "" {
// If no end is specified, range extends to end of the file.
r.End = size - 1
} else {
i, err := strconv.ParseInt(end, 10, 64)
if err != nil || r.Start > i {
return nil, ErrInvalid
ranges = append(ranges, &Range{
Start: start,
End: end,
})
}
if i >= size {
i = size - 1
}
r.End = i
}
}
ranges = append(ranges, r)
}
if noOverlap && len(ranges) == 0 {
// The specified ranges did not overlap with the content.
if len(ranges) == 0 {
return nil, ErrNoOverlap
}
return ranges, nil
}

View file

@ -499,7 +499,7 @@ func (fs *FileService) GetFileStream(c *gin.Context) {
end = file.Size - 1
w.WriteHeader(http.StatusOK)
} else {
ranges, err := http_range.ParseRange(rangeHeader, file.Size)
ranges, err := http_range.Parse(rangeHeader, file.Size)
if err == http_range.ErrNoOverlap {
w.Header().Set("Content-Range", fmt.Sprintf("bytes */%d", file.Size))
http.Error(w, http_range.ErrNoOverlap.Error(), http.StatusRequestedRangeNotSatisfiable)