<commit_before>package gofakes3

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

type ObjectRange struct {
	Start, Length int64
}

var zeroRange ObjectRange

func (o ObjectRange) IsZero() bool { return o == zeroRange }

func (o ObjectRange) writeHeader(sz int64, w http.ResponseWriter) {
	if !o.IsZero() {
		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", o.Start, o.Start+o.Length-1, sz))
		w.Header().Set("Content-Length", fmt.Sprintf("%d", o.Length))
	} else {
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
	}
}

type ObjectRangeRequest struct {
	Start, End int64
	FromEnd    bool
}

var zeroRangeRequest ObjectRangeRequest

func (o ObjectRangeRequest) IsZero() bool { return o == zeroRangeRequest }

func (o ObjectRangeRequest) Range(size int64) ObjectRange {
	var start, length int64

	if !o.FromEnd {
		// If no end is specified, range extends to end of the file.
		start = o.Start
		end := o.End
		if end >= size {
			end = size - 1
		}
		if o.End == 0 {
			length = size - o.Start
		} else {
			length = end - o.Start + 1
		}

	} else {
		// If no start is specified, end specifies the range start relative
		// to the end of the file.
		end := o.End
		if end > size {
			end = size
		}
		start = size - end
		length = size - start

	}

	return ObjectRange{Start: start, Length: length}
}

// parseHeader takes a bit of a shortcut and fails if you pass multiple ranges.
// Need to verify whether S3 supports this as it will lead to a backward
// compatibilty break in the Backend struct. May never be a problem in practice.
func (o *ObjectRangeRequest) parseHeader(s string) error {
	if s == "" {
		return nil
	}

	const b = "bytes="
	if !strings.HasPrefix(s, b) {
		return ErrInvalidRange
	}

	ranges := strings.Split(s[len(b):], ",")
	if len(ranges) > 1 {
		return ErrorMessage(ErrNotImplemented, "multiple ranges not supported")
	}

	rnge := strings.TrimSpace(ranges[0])
	if len(rnge) == 0 {
		return nil
	}<commit_msg>Clarify docs<commit_after>package gofakes3

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
)

type ObjectRange struct {
	Start, Length int64
}

var zeroRange ObjectRange

func (o ObjectRange) IsZero() bool { return o == zeroRange }

func (o ObjectRange) writeHeader(sz int64, w http.ResponseWriter) {
	if !o.IsZero() {
		w.Header().Set("Content-Range", fmt.Sprintf("bytes %d-%d/%d", o.Start, o.Start+o.Length-1, sz))
		w.Header().Set("Content-Length", fmt.Sprintf("%d", o.Length))
	} else {
		w.Header().Set("Content-Length", fmt.Sprintf("%d", sz))
	}
}

type ObjectRangeRequest struct {
	Start, End int64
	FromEnd    bool
}

var zeroRangeRequest ObjectRangeRequest

func (o ObjectRangeRequest) IsZero() bool { return o == zeroRangeRequest }

func (o ObjectRangeRequest) Range(size int64) ObjectRange {
	var start, length int64

	if !o.FromEnd {
		// If no end is specified, range extends to end of the file.
		start = o.Start
		end := o.End
		if end >= size {
			end = size - 1
		}
		if o.End == 0 {
			length = size - o.Start
		} else {
			length = end - o.Start + 1
		}

	} else {
		// If no start is specified, end specifies the range start relative
		// to the end of the file.
		end := o.End
		if end > size {
			end = size
		}
		start = size - end
		length = size - start

	}

	return ObjectRange{Start: start, Length: length}
}

// parseHeader parses a single byte range from the Range header.
//
// Amazon S3 doesn't support retrieving multiple ranges of data per GET request:
// https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectGET.html
func (o *ObjectRangeRequest) parseHeader(s string) error {
	if s == "" {
		return nil
	}

	const b = "bytes="
	if !strings.HasPrefix(s, b) {
		return ErrInvalidRange
	}

	ranges := strings.Split(s[len(b):], ",")
	if len(ranges) > 1 {
		return ErrorMessage(ErrNotImplemented, "multiple ranges not supported")
	}

	rnge := strings.TrimSpace(ranges[0])
	if len(rnge) == 0 {
		return nil
	}
{'fraction_non_alphanumeric': 0.13031233998975936, 'fraction_numerical': 0.009984639016897081, 'mean_word_length': 3.3556298773690076, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 9, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6280558', 'n_tokens_mistral': 1444, 'n_tokens_neox': 1338, 'n_words': 429}