mirror of
https://github.com/tgdrive/teldrive.git
synced 2024-09-20 08:15:55 +08:00
change http range func
This commit is contained in:
parent
1e2da6d627
commit
0a1c5d679e
|
@ -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
|
||||
}
|
||||
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
|
||||
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
|
||||
}
|
||||
if i >= size {
|
||||
i = size - 1
|
||||
}
|
||||
r.End = i
|
||||
}
|
||||
|
||||
if end >= size64 {
|
||||
end = size64 - 1
|
||||
}
|
||||
ranges = append(ranges, r)
|
||||
|
||||
if start > end || start < 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
ranges = append(ranges, &Range{
|
||||
Start: start,
|
||||
End: end,
|
||||
})
|
||||
}
|
||||
if noOverlap && len(ranges) == 0 {
|
||||
// The specified ranges did not overlap with the content.
|
||||
|
||||
if len(ranges) == 0 {
|
||||
return nil, ErrNoOverlap
|
||||
}
|
||||
|
||||
return ranges, nil
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue