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  }