From: Jed Denlea Date: Tue, 16 Dec 2014 08:24:19 +0000 (-0800) Subject: net/http: Fix Range off-by-one error X-Git-Tag: go1.5beta1~2577 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=474ce6903b0646101769b03e976f7f70527bab54;p=gostls13.git net/http: Fix Range off-by-one error Given a file of size N, a request for "Range: bytes=N-*" should return a 416 [1]. Currently, it returns a 206 and a body of 0 bytes, with the illegal Content-Range of "bytes N-(N-1)/N" [2]. [1]: RFC 7233, sec 2.1: "If a valid byte-range-set includes at least one byte-range-spec with a first-byte-pos that is less than the current length of the representation, [...]". sec 3.1: "If all of the preconditions are true, the server supports the Range header field for the target resource, and the specified range(s) are invalid or unsatisfiable, the server SHOULD send a 416 (Range Not Satisfiable) response." [2]: RFC 7233, sec 4.2: "A Content-Range field value is invalid if it contains a byte-range-resp that has a last-byte-pos value less than its first-byte-pos value, [...]" Fixes #8988 Change-Id: If3e1134e7815f5d361efea01873b29aafe3de817 Reviewed-on: https://go-review.googlesource.com/1862 Reviewed-by: Brad Fitzpatrick --- diff --git a/src/net/http/fs.go b/src/net/http/fs.go index e322f710a5..9a80123f6d 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -503,7 +503,7 @@ func parseRange(s string, size int64) ([]httpRange, error) { r.length = size - r.start } else { i, err := strconv.ParseInt(start, 10, 64) - if err != nil || i > size || i < 0 { + if err != nil || i >= size || i < 0 { return nil, errors.New("invalid range") } r.start = i diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index 8770d9b410..72f8c2cf1d 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -50,15 +50,23 @@ var ServeFileRangeTests = []struct { {r: "bytes=2-", code: StatusPartialContent, ranges: []wantRange{{2, testFileLen}}}, {r: "bytes=-5", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 5, testFileLen}}}, {r: "bytes=3-7", code: StatusPartialContent, ranges: []wantRange{{3, 8}}}, - {r: "bytes=20-", code: StatusRequestedRangeNotSatisfiable}, {r: "bytes=0-0,-2", code: StatusPartialContent, ranges: []wantRange{{0, 1}, {testFileLen - 2, testFileLen}}}, {r: "bytes=0-1,5-8", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, 9}}}, {r: "bytes=0-1,5-", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, testFileLen}}}, {r: "bytes=5-1000", code: StatusPartialContent, ranges: []wantRange{{5, testFileLen}}}, {r: "bytes=0-,1-,2-,3-,4-", code: StatusOK}, // ignore wasteful range request - {r: "bytes=0-" + itoa(testFileLen-2), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}}, - {r: "bytes=0-" + itoa(testFileLen-1), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, - {r: "bytes=0-" + itoa(testFileLen), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=0-9", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}}, + {r: "bytes=0-10", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=0-11", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=10-11", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}}, + {r: "bytes=10-", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}}, + {r: "bytes=11-", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=11-12", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=12-12", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=11-100", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=12-100", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=100-", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=100-1000", code: StatusRequestedRangeNotSatisfiable}, } func TestServeFile(t *testing.T) {