parseRange parses a Range header string as per RFC 7233. errNoOverlap is returned if none of the ranges overlap.
(s string, size int64)
| 980 | // parseRange parses a Range header string as per RFC 7233. |
| 981 | // errNoOverlap is returned if none of the ranges overlap. |
| 982 | func parseRange(s string, size int64) ([]httpRange, error) { |
| 983 | if s == "" { |
| 984 | return nil, nil // header not present |
| 985 | } |
| 986 | const b = "bytes=" |
| 987 | if !strings.HasPrefix(s, b) { |
| 988 | return nil, errors.New("invalid range") |
| 989 | } |
| 990 | var ranges []httpRange |
| 991 | noOverlap := false |
| 992 | for _, ra := range strings.Split(s[len(b):], ",") { |
| 993 | ra = textproto.TrimString(ra) |
| 994 | if ra == "" { |
| 995 | continue |
| 996 | } |
| 997 | start, end, ok := strings.Cut(ra, "-") |
| 998 | if !ok { |
| 999 | return nil, errors.New("invalid range") |
| 1000 | } |
| 1001 | start, end = textproto.TrimString(start), textproto.TrimString(end) |
| 1002 | var r httpRange |
| 1003 | if start == "" { |
| 1004 | // If no start is specified, end specifies the |
| 1005 | // range start relative to the end of the file, |
| 1006 | // and we are dealing with <suffix-length> |
| 1007 | // which has to be a non-negative integer as per |
| 1008 | // RFC 7233 Section 2.1 "Byte-Ranges". |
| 1009 | if end == "" || end[0] == '-' { |
| 1010 | return nil, errors.New("invalid range") |
| 1011 | } |
| 1012 | i, err := strconv.ParseInt(end, 10, 64) |
| 1013 | if i < 0 || err != nil { |
| 1014 | return nil, errors.New("invalid range") |
| 1015 | } |
| 1016 | if i > size { |
| 1017 | i = size |
| 1018 | } |
| 1019 | r.start = size - i |
| 1020 | r.length = size - r.start |
| 1021 | } else { |
| 1022 | i, err := strconv.ParseInt(start, 10, 64) |
| 1023 | if err != nil || i < 0 { |
| 1024 | return nil, errors.New("invalid range") |
| 1025 | } |
| 1026 | if i >= size { |
| 1027 | // If the range begins after the size of the content, |
| 1028 | // then it does not overlap. |
| 1029 | noOverlap = true |
| 1030 | continue |
| 1031 | } |
| 1032 | r.start = i |
| 1033 | if end == "" { |
| 1034 | // If no end is specified, range extends to end of the file. |
| 1035 | r.length = size - r.start |
| 1036 | } else { |
| 1037 | i, err := strconv.ParseInt(end, 10, 64) |
| 1038 | if err != nil || r.start > i { |
| 1039 | return nil, errors.New("invalid range") |