Commit f5037ee1 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: make ServeContent support dates in If-Range headers

Fixes #8367

LGTM=adg
R=adg
CC=golang-codereviews
https://golang.org/cl/116300044
parent 20a5de9e
...@@ -139,7 +139,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, ...@@ -139,7 +139,7 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
if checkLastModified(w, r, modtime) { if checkLastModified(w, r, modtime) {
return return
} }
rangeReq, done := checkETag(w, r) rangeReq, done := checkETag(w, r, modtime)
if done { if done {
return return
} }
...@@ -275,11 +275,14 @@ func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool { ...@@ -275,11 +275,14 @@ func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
} }
// checkETag implements If-None-Match and If-Range checks. // checkETag implements If-None-Match and If-Range checks.
// The ETag must have been previously set in the ResponseWriter's headers. //
// The ETag or modtime must have been previously set in the
// ResponseWriter's headers. The modtime is only compared at second
// granularity and may be the zero value to mean unknown.
// //
// The return value is the effective request "Range" header to use and // The return value is the effective request "Range" header to use and
// whether this request is now considered done. // whether this request is now considered done.
func checkETag(w ResponseWriter, r *Request) (rangeReq string, done bool) { func checkETag(w ResponseWriter, r *Request, modtime time.Time) (rangeReq string, done bool) {
etag := w.Header().get("Etag") etag := w.Header().get("Etag")
rangeReq = r.Header.get("Range") rangeReq = r.Header.get("Range")
...@@ -290,12 +293,18 @@ func checkETag(w ResponseWriter, r *Request) (rangeReq string, done bool) { ...@@ -290,12 +293,18 @@ func checkETag(w ResponseWriter, r *Request) (rangeReq string, done bool) {
// We only support ETag versions. // We only support ETag versions.
// The caller must have set the ETag on the response already. // The caller must have set the ETag on the response already.
if ir := r.Header.get("If-Range"); ir != "" && ir != etag { if ir := r.Header.get("If-Range"); ir != "" && ir != etag {
// TODO(bradfitz): handle If-Range requests with Last-Modified // The If-Range value is typically the ETag value, but it may also be
// times instead of ETags? I'd rather not, at least for // the modtime date. See golang.org/issue/8367.
// now. That seems like a bug/compromise in the RFC 2616, and timeMatches := false
// I've never heard of anybody caring about that (yet). if !modtime.IsZero() {
if t, err := ParseTime(ir); err == nil && t.Unix() == modtime.Unix() {
timeMatches = true
}
}
if !timeMatches {
rangeReq = "" rangeReq = ""
} }
}
if inm := r.Header.get("If-None-Match"); inm != "" { if inm := r.Header.get("If-None-Match"); inm != "" {
// Must know ETag. // Must know ETag.
......
...@@ -721,6 +721,28 @@ func TestServeContent(t *testing.T) { ...@@ -721,6 +721,28 @@ func TestServeContent(t *testing.T) {
wantStatus: 200, wantStatus: 200,
wantContentType: "text/css; charset=utf-8", wantContentType: "text/css; charset=utf-8",
}, },
"range_with_modtime": {
file: "testdata/style.css",
modtime: time.Date(2014, 6, 25, 17, 12, 18, 0 /* nanos */, time.UTC),
reqHeader: map[string]string{
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
wantStatus: StatusPartialContent,
wantContentType: "text/css; charset=utf-8",
wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
"range_with_modtime_nanos": {
file: "testdata/style.css",
modtime: time.Date(2014, 6, 25, 17, 12, 18, 123 /* nanos */, time.UTC),
reqHeader: map[string]string{
"Range": "bytes=0-4",
"If-Range": "Wed, 25 Jun 2014 17:12:18 GMT",
},
wantStatus: StatusPartialContent,
wantContentType: "text/css; charset=utf-8",
wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT",
},
} }
for testName, tt := range tests { for testName, tt := range tests {
var content io.ReadSeeker var content io.ReadSeeker
......
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