Commit 474ce690 authored by Jed Denlea's avatar Jed Denlea Committed by Brad Fitzpatrick

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/1862Reviewed-by: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 640c0f38
......@@ -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
......
......@@ -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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment