Range returns a struct containing the type and a slice of ranges.
(size int64)
| 1019 | |
| 1020 | // Range returns a struct containing the type and a slice of ranges. |
| 1021 | func (r *DefaultReq) Range(size int64) (Range, error) { |
| 1022 | var ( |
| 1023 | rangeData Range |
| 1024 | ranges string |
| 1025 | ) |
| 1026 | rangeStr := utils.TrimSpace(r.Get(HeaderRange)) |
| 1027 | maxRanges := r.c.app.config.MaxRanges |
| 1028 | const maxRangePrealloc = 8 |
| 1029 | prealloc := min(maxRanges, maxRangePrealloc) |
| 1030 | if prealloc > 0 { |
| 1031 | rangeData.Ranges = make([]RangeSet, 0, prealloc) |
| 1032 | } |
| 1033 | |
| 1034 | parseBound := func(value string) (int64, error) { |
| 1035 | if value == "" { // empty bound (suffix/prefix range); skip the parser's error alloc |
| 1036 | return 0, errRangeBound |
| 1037 | } |
| 1038 | parsed, err := utils.ParseUint(value) |
| 1039 | if err != nil { |
| 1040 | return 0, errRangeBound // sentinel: never surfaced, avoids per-request alloc |
| 1041 | } |
| 1042 | if parsed > (math.MaxUint64 >> 1) { |
| 1043 | return 0, ErrRangeMalformed |
| 1044 | } |
| 1045 | return int64(parsed), nil |
| 1046 | } |
| 1047 | |
| 1048 | before, after, found := strings.Cut(rangeStr, "=") |
| 1049 | if !found || strings.IndexByte(after, '=') >= 0 { |
| 1050 | return rangeData, ErrRangeMalformed |
| 1051 | } |
| 1052 | rangeData.Type = utilsstrings.ToLower(utils.TrimSpace(before)) |
| 1053 | if rangeData.Type != "bytes" { |
| 1054 | return rangeData, ErrRangeMalformed |
| 1055 | } |
| 1056 | ranges = utils.TrimSpace(after) |
| 1057 | |
| 1058 | var ( |
| 1059 | singleRange string |
| 1060 | moreRanges = ranges |
| 1061 | rangeCount int |
| 1062 | ) |
| 1063 | for moreRanges != "" { |
| 1064 | rangeCount++ |
| 1065 | if rangeCount > maxRanges { |
| 1066 | r.c.DefaultRes.Status(StatusRequestedRangeNotSatisfiable) |
| 1067 | r.c.DefaultRes.Set(HeaderContentRange, "bytes */"+utils.FormatInt(size)) //nolint:staticcheck // It is fine to ignore the static check |
| 1068 | return rangeData, ErrRangeTooLarge |
| 1069 | } |
| 1070 | singleRange = moreRanges |
| 1071 | if i := strings.IndexByte(moreRanges, ','); i >= 0 { |
| 1072 | singleRange = moreRanges[:i] |
| 1073 | moreRanges = utils.TrimSpace(moreRanges[i+1:]) |
| 1074 | } else { |
| 1075 | moreRanges = "" |
| 1076 | } |
| 1077 | |
| 1078 | singleRange = utils.TrimSpace(singleRange) |