github.com/0chain/gosdk@v1.17.11/winsdk/stream_models.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "net/textproto" 7 "strconv" 8 "strings" 9 ) 10 11 var errNoOverlap = errors.New("invalid range: failed to overlap") 12 13 type httpRange struct { 14 start, length, total int64 15 } 16 17 func (r httpRange) Header() string { 18 return fmt.Sprintf("bytes %d-%d/%d", r.start, r.start+r.length-1, r.total) 19 } 20 21 // parseRange parses a Range header string as per RFC 7233. 22 // errNoOverlap is returned if none of the ranges overlap. 23 // 24 // Examples of valid byte ranges (assuming a resource of length 10240): 25 // bytes=0-499, the first 500 bytes 26 // bytes=1000-1999, 1000 bytes start from offset 1000 27 // bytes=-500, the final 500 bytes (byte offsets 9739-10239, inclusive) 28 // bytes=0-0,-1, the first and last bytes only 29 // bytes=0-, bytes=0-10250, be interpreted as bytes=0-10239 30 func parseRange(s string, total int64) ([]httpRange, error) { 31 if s == "" { 32 return nil, nil // header not present 33 } 34 const b = "bytes=" 35 if !strings.HasPrefix(s, b) { 36 return nil, errors.New("invalid range") 37 } 38 var ranges []httpRange 39 noOverlap := false 40 for _, ra := range strings.Split(s[len(b):], ",") { 41 ra = textproto.TrimString(ra) 42 if ra == "" { 43 continue 44 } 45 start, end, ok := strings.Cut(ra, "-") 46 if !ok { 47 return nil, errors.New("invalid range") 48 } 49 start, end = textproto.TrimString(start), textproto.TrimString(end) 50 var r httpRange 51 if start == "" { 52 if end == "" || end[0] == '-' { 53 return nil, errors.New("invalid range") 54 } 55 i, err := strconv.ParseInt(end, 10, 64) 56 if i < 0 || err != nil { 57 return nil, errors.New("invalid range") 58 } 59 if i > total { 60 i = total 61 } 62 r.start = total - i 63 r.length = total - r.start 64 } else { 65 i, err := strconv.ParseInt(start, 10, 64) 66 if err != nil || i < 0 { 67 return nil, errors.New("invalid range") 68 } 69 if i >= total { 70 // If the range begins after the size of the content, 71 // then it does not overlap. 72 noOverlap = true 73 i = total - 1 74 //continue, since server may attempt to return a largeEnoughLen, errNoOverlap never happen 75 } 76 r.start = i 77 if end == "" { 78 r.length = sizePerRequest 79 if r.length > total-r.start && !noOverlap { 80 r.length = total - r.start 81 } 82 } else { 83 i, err := strconv.ParseInt(end, 10, 64) 84 if err != nil || r.start > i { 85 return nil, errors.New("invalid range") 86 } 87 if i >= total { 88 i = total - 1 89 } 90 r.length = i - r.start + 1 91 } 92 } 93 r.total = total 94 ranges = append(ranges, r) 95 } 96 if noOverlap && len(ranges) == 0 { 97 // The specified ranges did not overlap with the content. 98 return nil, errNoOverlap 99 } 100 return ranges, nil 101 }