[Client] Fix error in parsing of 'Range' header.

* Result of regexp.FindStringSubmatch must be checked to be not nil.
Otherwise it leads to `index out of range`.
* Range header regexp is compiled only once to speedup (5x) the header parsing.

Signed-off-by: Anton Tiurin <noxiouz@yandex.ru>
This commit is contained in:
Anton Tiurin 2015-02-03 00:34:38 +03:00
parent e492579718
commit 9c0519c4ed
2 changed files with 43 additions and 5 deletions

View file

@ -67,6 +67,10 @@ type Client interface {
CancelBlobUpload(location string) error CancelBlobUpload(location string) error
} }
var (
patternRangeHeader = regexp.MustCompile("bytes=0-(\\d+)/(\\d+)")
)
// New returns a new Client which operates against a registry with the // New returns a new Client which operates against a registry with the
// given base endpoint // given base endpoint
// This endpoint should not include /v2/ or any part of the url after this. // This endpoint should not include /v2/ or any part of the url after this.
@ -553,15 +557,18 @@ func (r *clientImpl) CancelBlobUpload(location string) error {
// parseRangeHeader parses out the offset and length from a returned Range // parseRangeHeader parses out the offset and length from a returned Range
// header // header
func parseRangeHeader(byteRangeHeader string) (int, int, error) { func parseRangeHeader(byteRangeHeader string) (int, int, error) {
r := regexp.MustCompile("bytes=0-(\\d+)/(\\d+)") submatches := patternRangeHeader.FindStringSubmatch(byteRangeHeader)
submatches := r.FindStringSubmatch(byteRangeHeader) if submatches == nil || len(submatches) < 3 {
offset, err := strconv.ParseInt(submatches[1], 10, 0) return 0, 0, fmt.Errorf("Malformed Range header")
}
offset, err := strconv.Atoi(submatches[1])
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
length, err := strconv.ParseInt(submatches[2], 10, 0) length, err := strconv.Atoi(submatches[2])
if err != nil { if err != nil {
return 0, 0, err return 0, 0, err
} }
return int(offset), int(length), nil return offset, length, nil
} }

View file

@ -19,6 +19,37 @@ type testBlob struct {
contents []byte contents []byte
} }
func TestRangeHeaderParser(t *testing.T) {
const (
malformedRangeHeader = "bytes=0-A/C"
emptyRangeHeader = ""
rFirst = 100
rSecond = 200
)
var (
wellformedRangeHeader = fmt.Sprintf("bytes=0-%d/%d", rFirst, rSecond)
)
if _, _, err := parseRangeHeader(malformedRangeHeader); err == nil {
t.Fatalf("malformedRangeHeader: error expected, got nil")
}
if _, _, err := parseRangeHeader(emptyRangeHeader); err == nil {
t.Fatalf("emptyRangeHeader: error expected, got nil")
}
first, second, err := parseRangeHeader(wellformedRangeHeader)
if err != nil {
t.Fatalf("wellformedRangeHeader: unexpected error %v", err)
}
if first != rFirst || second != rSecond {
t.Fatalf("Range has been parsed unproperly: %d/%d", first, second)
}
}
func TestPush(t *testing.T) { func TestPush(t *testing.T) {
name := "hello/world" name := "hello/world"
tag := "sometag" tag := "sometag"